home *** CD-ROM | disk | FTP | other *** search
/ PC go! 2014 May / PCgo_CD_14-05.iso / nw.pak / Unnamed File 000658.unknown < prev    next >
Encoding:
Text File  |  2012-12-14  |  241.2 KB  |  9,011 lines

  1.  
  2.  
  3.  
  4. const UserInitiatedProfileName = "org.webkit.profiles.user-initiated";
  5.  
  6.  
  7. WebInspector.ProfileType = function(id, name)
  8. {
  9. this._id = id;
  10. this._name = name;
  11.  
  12. this.treeElement = null;
  13. }
  14.  
  15. WebInspector.ProfileType.prototype = {
  16. get buttonTooltip()
  17. {
  18. return "";
  19. },
  20.  
  21. get id()
  22. {
  23. return this._id;
  24. },
  25.  
  26. get treeItemTitle()
  27. {
  28. return this._name;
  29. },
  30.  
  31. get name()
  32. {
  33. return this._name;
  34. },
  35.  
  36.  
  37. buttonClicked: function(profilesPanel)
  38. {
  39. return false;
  40. },
  41.  
  42. reset: function()
  43. {
  44. },
  45.  
  46. get description()
  47. {
  48. return "";
  49. },
  50.  
  51.  
  52.  
  53. createTemporaryProfile: function(title)
  54. {
  55. throw new Error("Needs implemented.");
  56. },
  57.  
  58.  
  59. createProfile: function(profile)
  60. {
  61. throw new Error("Not supported for " + this._name + " profiles.");
  62. }
  63. }
  64.  
  65.  
  66. WebInspector.ProfileHeader = function(profileType, title, uid)
  67. {
  68. this._profileType = profileType;
  69. this.title = title;
  70. if (uid === undefined) {
  71. this.uid = -1;
  72. this.isTemporary = true;
  73. } else {
  74. this.uid = uid;
  75. this.isTemporary = false;
  76. }
  77. this._fromFile = false;
  78. }
  79.  
  80. WebInspector.ProfileHeader.prototype = {
  81. profileType: function()
  82. {
  83. return this._profileType;
  84. },
  85.  
  86.  
  87. createSidebarTreeElement: function()
  88. {
  89. throw new Error("Needs implemented.");
  90. },
  91.  
  92. existingView: function()
  93. {
  94. return this._view;
  95. },
  96.  
  97. view: function()
  98. {
  99. if (!this._view)
  100. this._view = this.createView(WebInspector.ProfilesPanel._instance);
  101. return this._view;
  102. },
  103.  
  104.  
  105. createView: function(profilesPanel)
  106. {
  107. throw new Error("Not implemented.");
  108. },
  109.  
  110.  
  111. load: function(callback) { },
  112.  
  113.  
  114. canSaveToFile: function() { return false; },
  115.  
  116. saveToFile: function() { throw new Error("Needs implemented"); },
  117.  
  118.  
  119. canLoadFromFile: function() { return false; },
  120.  
  121.  
  122. loadFromFile: function(file) { throw new Error("Needs implemented"); },
  123.  
  124.  
  125. fromFile: function() { return this._fromFile; }
  126. }
  127.  
  128.  
  129. WebInspector.ProfilesPanel = function()
  130. {
  131. WebInspector.Panel.call(this, "profiles");
  132. WebInspector.ProfilesPanel._instance = this;
  133. this.registerRequiredCSS("panelEnablerView.css");
  134. this.registerRequiredCSS("heapProfiler.css");
  135. this.registerRequiredCSS("profilesPanel.css");
  136.  
  137. this.createSidebarViewWithTree();
  138.  
  139. this.profilesItemTreeElement = new WebInspector.ProfilesSidebarTreeElement(this);
  140. this.sidebarTree.appendChild(this.profilesItemTreeElement);
  141.  
  142. this._profileTypesByIdMap = {};
  143.  
  144. var panelEnablerHeading = WebInspector.UIString("You need to enable profiling before you can use the Profiles panel.");
  145. var panelEnablerDisclaimer = WebInspector.UIString("Enabling profiling will make scripts run slower.");
  146. var panelEnablerButton = WebInspector.UIString("Enable Profiling");
  147. this.panelEnablerView = new WebInspector.PanelEnablerView("profiles", panelEnablerHeading, panelEnablerDisclaimer, panelEnablerButton);
  148. this.panelEnablerView.addEventListener("enable clicked", this.enableProfiler, this);
  149.  
  150. this.profileViews = document.createElement("div");
  151. this.profileViews.id = "profile-views";
  152. this.splitView.mainElement.appendChild(this.profileViews);
  153.  
  154. this._statusBarButtons = [];
  155.  
  156. this.enableToggleButton = new WebInspector.StatusBarButton("", "enable-toggle-status-bar-item");
  157. if (Capabilities.profilerCausesRecompilation) {
  158. this._statusBarButtons.push(this.enableToggleButton);
  159. this.enableToggleButton.addEventListener("click", this._toggleProfiling, this);
  160. }
  161. this.recordButton = new WebInspector.StatusBarButton("", "record-profile-status-bar-item");
  162. this.recordButton.addEventListener("click", this.toggleRecordButton, this);
  163. this._statusBarButtons.push(this.recordButton);
  164.  
  165. this.clearResultsButton = new WebInspector.StatusBarButton(WebInspector.UIString("Clear all profiles."), "clear-status-bar-item");
  166. this.clearResultsButton.addEventListener("click", this._clearProfiles, this);
  167. this._statusBarButtons.push(this.clearResultsButton);
  168.  
  169. if (WebInspector.experimentsSettings.liveNativeMemoryChart.isEnabled()) {
  170. this.garbageCollectButton = new WebInspector.StatusBarButton(WebInspector.UIString("Collect Garbage"), "garbage-collect-status-bar-item");
  171. this.garbageCollectButton.addEventListener("click", this._garbageCollectButtonClicked, this);
  172. this._statusBarButtons.push(this.garbageCollectButton);
  173. }
  174.  
  175. this.profileViewStatusBarItemsContainer = document.createElement("div");
  176. this.profileViewStatusBarItemsContainer.className = "status-bar-items";
  177.  
  178. this._profiles = [];
  179. this._profilerEnabled = !Capabilities.profilerCausesRecompilation;
  180.  
  181. this._launcherView = new WebInspector.ProfileLauncherView(this);
  182. this._launcherView.addEventListener(WebInspector.ProfileLauncherView.EventTypes.ProfileTypeSelected, this._onProfileTypeSelected, this);
  183. this._reset();
  184.  
  185. this._registerProfileType(new WebInspector.CPUProfileType());
  186. if (!WebInspector.WorkerManager.isWorkerFrontend())
  187. this._registerProfileType(new WebInspector.CSSSelectorProfileType());
  188. if (Capabilities.heapProfilerPresent)
  189. this._registerProfileType(new WebInspector.HeapSnapshotProfileType());
  190. if (WebInspector.experimentsSettings.nativeMemorySnapshots.isEnabled())
  191. this._registerProfileType(new WebInspector.NativeMemoryProfileType());
  192. if (WebInspector.experimentsSettings.canvasInspection.isEnabled())
  193. this._registerProfileType(new WebInspector.CanvasProfileType());
  194.  
  195. InspectorBackend.registerProfilerDispatcher(new WebInspector.ProfilerDispatcher(this));
  196.  
  197. this._createFileSelectorElement();
  198. this.element.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true);
  199.  
  200. WebInspector.ContextMenu.registerProvider(this);
  201. }
  202.  
  203. WebInspector.ProfilesPanel.prototype = {
  204. _createFileSelectorElement: function()
  205. {
  206. if (this._fileSelectorElement)
  207. this.element.removeChild(this._fileSelectorElement);
  208. this._fileSelectorElement = WebInspector.createFileSelectorElement(this._loadFromFile.bind(this));
  209. this.element.appendChild(this._fileSelectorElement);
  210. },
  211.  
  212. _loadFromFile: function(file)
  213. {
  214. if (!file.name.endsWith(".heapsnapshot")) {
  215. WebInspector.log(WebInspector.UIString("Only heap snapshots from files with extension '.heapsnapshot' can be loaded."));
  216. return;
  217. }
  218.  
  219. if (!!this.findTemporaryProfile(WebInspector.HeapSnapshotProfileType.TypeId)) {
  220. WebInspector.log(WebInspector.UIString("Can't load profile when other profile is recording."));
  221. return;
  222. }
  223.  
  224. var profileType = this.getProfileType(WebInspector.HeapSnapshotProfileType.TypeId);
  225. var temporaryProfile = profileType.createTemporaryProfile(UserInitiatedProfileName + "." + file.name);
  226. this.addProfileHeader(temporaryProfile);
  227.  
  228. temporaryProfile._fromFile = true;
  229. temporaryProfile.loadFromFile(file);
  230. this._createFileSelectorElement();
  231. },
  232.  
  233. get statusBarItems()
  234. {
  235. return this._statusBarButtons.select("element").concat([this.profileViewStatusBarItemsContainer]);
  236. },
  237.  
  238. toggleRecordButton: function()
  239. {
  240. var isProfiling = this._selectedProfileType.buttonClicked(this);
  241. this.recordButton.toggled = isProfiling;
  242. this.recordButton.title = this._selectedProfileType.buttonTooltip;
  243. if (isProfiling)
  244. this._launcherView.profileStarted();
  245. else
  246. this._launcherView.profileFinished();
  247. },
  248.  
  249. wasShown: function()
  250. {
  251. WebInspector.Panel.prototype.wasShown.call(this);
  252. this._populateProfiles();
  253. },
  254.  
  255. _profilerWasEnabled: function()
  256. {
  257. if (this._profilerEnabled)
  258. return;
  259.  
  260. this._profilerEnabled = true;
  261.  
  262. this._reset();
  263. if (this.isShowing())
  264. this._populateProfiles();
  265. },
  266.  
  267. _profilerWasDisabled: function()
  268. {
  269. if (!this._profilerEnabled)
  270. return;
  271.  
  272. this._profilerEnabled = false;
  273. this._reset();
  274. },
  275.  
  276. _onProfileTypeSelected: function(event)
  277. {
  278. this._selectedProfileType = event.data;
  279. this.recordButton.title = this._selectedProfileType.buttonTooltip;
  280. },
  281.  
  282. _reset: function()
  283. {
  284. WebInspector.Panel.prototype.reset.call(this);
  285.  
  286. for (var i = 0; i < this._profiles.length; ++i) {
  287. var view = this._profiles[i].existingView();
  288. if (view) {
  289. view.detach();
  290. if ("dispose" in view)
  291. view.dispose();
  292. }
  293. }
  294. delete this.visibleView;
  295.  
  296. delete this.currentQuery;
  297. this.searchCanceled();
  298.  
  299. for (var id in this._profileTypesByIdMap) {
  300. var profileType = this._profileTypesByIdMap[id];
  301. var treeElement = profileType.treeElement;
  302. treeElement.removeChildren();
  303. treeElement.hidden = true;
  304. profileType.reset();
  305. }
  306.  
  307. this._profiles = [];
  308. this._profilesIdMap = {};
  309. this._profileGroups = {};
  310. this._profileGroupsForLinks = {};
  311. this._profilesWereRequested = false;
  312. this.recordButton.toggled = false;
  313. if (this._selectedProfileType)
  314. this.recordButton.title = this._selectedProfileType.buttonTooltip;
  315. this._launcherView.profileFinished();
  316.  
  317. this.sidebarTreeElement.removeStyleClass("some-expandable");
  318.  
  319. this.profileViews.removeChildren();
  320. this.profileViewStatusBarItemsContainer.removeChildren();
  321.  
  322. this.removeAllListeners();
  323.  
  324. this._updateInterface();
  325. this.profilesItemTreeElement.select();
  326. this._showLauncherView();
  327. },
  328.  
  329. _showLauncherView: function()
  330. {
  331. this.closeVisibleView();
  332. this.profileViewStatusBarItemsContainer.removeChildren();
  333. this._launcherView.show(this.splitView.mainElement);
  334. this.visibleView = this._launcherView;
  335. },
  336.  
  337. _clearProfiles: function()
  338. {
  339. ProfilerAgent.clearProfiles();
  340. this._reset();
  341. },
  342.  
  343. _garbageCollectButtonClicked: function()
  344. {
  345. ProfilerAgent.collectGarbage();
  346. },
  347.  
  348.  
  349. _registerProfileType: function(profileType)
  350. {
  351. this._profileTypesByIdMap[profileType.id] = profileType;
  352. this._launcherView.addProfileType(profileType);
  353. profileType.treeElement = new WebInspector.SidebarSectionTreeElement(profileType.treeItemTitle, null, true);
  354. profileType.treeElement.hidden = true;
  355. this.sidebarTree.appendChild(profileType.treeElement);
  356. profileType.treeElement.childrenListElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true);
  357. },
  358.  
  359. _handleContextMenuEvent: function(event)
  360. {
  361. var element = event.srcElement;
  362. while (element && !element.treeElement && element !== this.element)
  363. element = element.parentElement;
  364. if (!element)
  365. return;
  366. if (element.treeElement && element.treeElement.handleContextMenuEvent) {
  367. element.treeElement.handleContextMenuEvent(event);
  368. return;
  369. }
  370. if (element !== this.element || event.srcElement === this.sidebarElement) {
  371. var contextMenu = new WebInspector.ContextMenu(event);
  372. if (this.visibleView instanceof WebInspector.HeapSnapshotView)
  373. this.visibleView.populateContextMenu(contextMenu, event);
  374. contextMenu.appendItem(WebInspector.UIString("Load Heap Snapshot\u2026"), this._fileSelectorElement.click.bind(this._fileSelectorElement));
  375. contextMenu.show();
  376. }
  377.  
  378. },
  379.  
  380.  
  381. _makeTitleKey: function(text, profileTypeId)
  382. {
  383. return escape(text) + '/' + escape(profileTypeId);
  384. },
  385.  
  386.  
  387. _makeKey: function(id, profileTypeId)
  388. {
  389. return id + '/' + escape(profileTypeId);
  390. },
  391.  
  392.  
  393. addProfileHeader: function(profile)
  394. {
  395. this._removeTemporaryProfile(profile.profileType().id);
  396.  
  397. var profileType = profile.profileType();
  398. var typeId = profileType.id;
  399. var sidebarParent = profileType.treeElement;
  400. sidebarParent.hidden = false;
  401. var small = false;
  402. var alternateTitle;
  403.  
  404. this._profiles.push(profile);
  405. this._profilesIdMap[this._makeKey(profile.uid, typeId)] = profile;
  406.  
  407. if (!profile.title.startsWith(UserInitiatedProfileName)) {
  408. var profileTitleKey = this._makeTitleKey(profile.title, typeId);
  409. if (!(profileTitleKey in this._profileGroups))
  410. this._profileGroups[profileTitleKey] = [];
  411.  
  412. var group = this._profileGroups[profileTitleKey];
  413. group.push(profile);
  414.  
  415. if (group.length === 2) {
  416.  
  417. group._profilesTreeElement = new WebInspector.ProfileGroupSidebarTreeElement(profile.title);
  418.  
  419.  
  420. var index = sidebarParent.children.indexOf(group[0]._profilesTreeElement);
  421. sidebarParent.insertChild(group._profilesTreeElement, index);
  422.  
  423.  
  424. var selected = group[0]._profilesTreeElement.selected;
  425. sidebarParent.removeChild(group[0]._profilesTreeElement);
  426. group._profilesTreeElement.appendChild(group[0]._profilesTreeElement);
  427. if (selected)
  428. group[0]._profilesTreeElement.revealAndSelect();
  429.  
  430. group[0]._profilesTreeElement.small = true;
  431. group[0]._profilesTreeElement.mainTitle = WebInspector.UIString("Run %d", 1);
  432.  
  433. this.sidebarTreeElement.addStyleClass("some-expandable");
  434. }
  435.  
  436. if (group.length >= 2) {
  437. sidebarParent = group._profilesTreeElement;
  438. alternateTitle = WebInspector.UIString("Run %d", group.length);
  439. small = true;
  440. }
  441. }
  442.  
  443. var profileTreeElement = profile.createSidebarTreeElement();
  444. profile.sidebarElement = profileTreeElement;
  445. profileTreeElement.small = small;
  446. if (alternateTitle)
  447. profileTreeElement.mainTitle = alternateTitle;
  448. profile._profilesTreeElement = profileTreeElement;
  449.  
  450. sidebarParent.appendChild(profileTreeElement);
  451. if (!profile.isTemporary) {
  452. if (!this.visibleView)
  453. this.showProfile(profile);
  454. this.dispatchEventToListeners("profile added");
  455. }
  456. },
  457.  
  458.  
  459. _removeProfileHeader: function(profile)
  460. {
  461. var sidebarParent = profile.profileType().treeElement;
  462.  
  463. for (var i = 0; i < this._profiles.length; ++i) {
  464. if (this._profiles[i].uid === profile.uid) {
  465. profile = this._profiles[i];
  466. this._profiles.splice(i, 1);
  467. break;
  468. }
  469. }
  470. delete this._profilesIdMap[this._makeKey(profile.uid, profile.profileType().id)];
  471.  
  472. var profileTitleKey = this._makeTitleKey(profile.title, profile.profileType().id);
  473. delete this._profileGroups[profileTitleKey];
  474.  
  475. sidebarParent.removeChild(profile._profilesTreeElement);
  476.  
  477. if (!profile.isTemporary)
  478. ProfilerAgent.removeProfile(profile.profileType().id, profile.uid);
  479.  
  480.  
  481.  
  482. if (!this._profiles.length)
  483. this.closeVisibleView();
  484. },
  485.  
  486.  
  487. showProfile: function(profile)
  488. {
  489. if (!profile || profile.isTemporary)
  490. return;
  491.  
  492. var view = profile.view();
  493. if (view === this.visibleView)
  494. return;
  495.  
  496. this.closeVisibleView();
  497.  
  498. view.show(this.profileViews);
  499.  
  500. profile._profilesTreeElement._suppressOnSelect = true;
  501. profile._profilesTreeElement.revealAndSelect();
  502. delete profile._profilesTreeElement._suppressOnSelect;
  503.  
  504. this.visibleView = view;
  505.  
  506. this.profileViewStatusBarItemsContainer.removeChildren();
  507.  
  508. var statusBarItems = view.statusBarItems;
  509. if (statusBarItems)
  510. for (var i = 0; i < statusBarItems.length; ++i)
  511. this.profileViewStatusBarItemsContainer.appendChild(statusBarItems[i]);
  512. },
  513.  
  514.  
  515. getProfiles: function(typeId)
  516. {
  517. var result = [];
  518. var profilesCount = this._profiles.length;
  519. for (var i = 0; i < profilesCount; ++i) {
  520. var profile = this._profiles[i];
  521. if (!profile.isTemporary && profile.profileType().id === typeId)
  522. result.push(profile);
  523. }
  524. return result;
  525. },
  526.  
  527.  
  528. showObject: function(snapshotObjectId, viewName)
  529. {
  530. var heapProfiles = this.getProfiles(WebInspector.HeapSnapshotProfileType.TypeId);
  531. for (var i = 0; i < heapProfiles.length; i++) {
  532. var profile = heapProfiles[i];
  533.  
  534. if (profile.maxJSObjectId >= snapshotObjectId) {
  535. this.showProfile(profile);
  536. profile.view().changeView(viewName, function() {
  537. profile.view().dataGrid.highlightObjectByHeapSnapshotId(snapshotObjectId);
  538. });
  539. break;
  540. }
  541. }
  542. },
  543.  
  544.  
  545. findTemporaryProfile: function(typeId)
  546. {
  547. var profilesCount = this._profiles.length;
  548. for (var i = 0; i < profilesCount; ++i)
  549. if (this._profiles[i].profileType().id === typeId && this._profiles[i].isTemporary)
  550. return this._profiles[i];
  551. return null;
  552. },
  553.  
  554.  
  555. _removeTemporaryProfile: function(typeId)
  556. {
  557. var temporaryProfile = this.findTemporaryProfile(typeId);
  558. if (temporaryProfile)
  559. this._removeProfileHeader(temporaryProfile);
  560. },
  561.  
  562.  
  563. getProfile: function(typeId, uid)
  564. {
  565. return this._profilesIdMap[this._makeKey(uid, typeId)];
  566. },
  567.  
  568.  
  569. _addHeapSnapshotChunk: function(uid, chunk)
  570. {
  571. var profile = this._profilesIdMap[this._makeKey(uid, WebInspector.HeapSnapshotProfileType.TypeId)];
  572. if (!profile)
  573. return;
  574. profile.transferChunk(chunk);
  575. },
  576.  
  577.  
  578. _finishHeapSnapshot: function(uid)
  579. {
  580. var profile = this._profilesIdMap[this._makeKey(uid, WebInspector.HeapSnapshotProfileType.TypeId)];
  581. if (!profile)
  582. return;
  583. profile.finishHeapSnapshot();
  584. },
  585.  
  586.  
  587. showView: function(view)
  588. {
  589. this.showProfile(view.profile);
  590. },
  591.  
  592.  
  593. getProfileType: function(typeId)
  594. {
  595. return this._profileTypesByIdMap[typeId];
  596. },
  597.  
  598.  
  599. showProfileForURL: function(url)
  600. {
  601. var match = url.match(WebInspector.ProfileURLRegExp);
  602. if (!match)
  603. return;
  604. this.showProfile(this._profilesIdMap[this._makeKey(Number(match[3]), match[1])]);
  605. },
  606.  
  607. closeVisibleView: function()
  608. {
  609. if (this.visibleView)
  610. this.visibleView.detach();
  611. delete this.visibleView;
  612. },
  613.  
  614.  
  615. displayTitleForProfileLink: function(title, typeId)
  616. {
  617. title = unescape(title);
  618. if (title.startsWith(UserInitiatedProfileName)) {
  619. title = WebInspector.UIString("Profile %d", title.substring(UserInitiatedProfileName.length + 1));
  620. } else {
  621. var titleKey = this._makeTitleKey(title, typeId);
  622. if (!(titleKey in this._profileGroupsForLinks))
  623. this._profileGroupsForLinks[titleKey] = 0;
  624.  
  625. var groupNumber = ++this._profileGroupsForLinks[titleKey];
  626.  
  627. if (groupNumber > 2)
  628.  
  629.  
  630. title += " " + WebInspector.UIString("Run %d", (groupNumber + 1) / 2);
  631. }
  632.  
  633. return title;
  634. },
  635.  
  636.  
  637. performSearch: function(query)
  638. {
  639. this.searchCanceled();
  640.  
  641. var searchableViews = this._searchableViews();
  642. if (!searchableViews || !searchableViews.length)
  643. return;
  644.  
  645. var visibleView = this.visibleView;
  646.  
  647. var matchesCountUpdateTimeout = null;
  648.  
  649. function updateMatchesCount()
  650. {
  651. WebInspector.searchController.updateSearchMatchesCount(this._totalSearchMatches, this);
  652. WebInspector.searchController.updateCurrentMatchIndex(this._currentSearchResultIndex, this);
  653. matchesCountUpdateTimeout = null;
  654. }
  655.  
  656. function updateMatchesCountSoon()
  657. {
  658. if (matchesCountUpdateTimeout)
  659. return;
  660.  
  661. matchesCountUpdateTimeout = setTimeout(updateMatchesCount.bind(this), 500);
  662. }
  663.  
  664. function finishedCallback(view, searchMatches)
  665. {
  666. if (!searchMatches)
  667. return;
  668.  
  669. this._totalSearchMatches += searchMatches;
  670. this._searchResults.push(view);
  671.  
  672. if (this.searchMatchFound)
  673. this.searchMatchFound(view, searchMatches);
  674.  
  675. updateMatchesCountSoon.call(this);
  676.  
  677. if (view === visibleView)
  678. view.jumpToFirstSearchResult();
  679. }
  680.  
  681. var i = 0;
  682. var panel = this;
  683. var boundFinishedCallback = finishedCallback.bind(this);
  684. var chunkIntervalIdentifier = null;
  685.  
  686.  
  687.  
  688.  
  689. function processChunk()
  690. {
  691. var view = searchableViews[i];
  692.  
  693. if (++i >= searchableViews.length) {
  694. if (panel._currentSearchChunkIntervalIdentifier === chunkIntervalIdentifier)
  695. delete panel._currentSearchChunkIntervalIdentifier;
  696. clearInterval(chunkIntervalIdentifier);
  697. }
  698.  
  699. if (!view)
  700. return;
  701.  
  702. view.currentQuery = query;
  703. view.performSearch(query, boundFinishedCallback);
  704. }
  705.  
  706. processChunk();
  707.  
  708. chunkIntervalIdentifier = setInterval(processChunk, 25);
  709. this._currentSearchChunkIntervalIdentifier = chunkIntervalIdentifier;
  710. },
  711.  
  712. jumpToNextSearchResult: function()
  713. {
  714. if (!this.showView || !this._searchResults || !this._searchResults.length)
  715. return;
  716.  
  717. var showFirstResult = false;
  718.  
  719. this._currentSearchResultIndex = this._searchResults.indexOf(this.visibleView);
  720. if (this._currentSearchResultIndex === -1) {
  721. this._currentSearchResultIndex = 0;
  722. showFirstResult = true;
  723. }
  724.  
  725. var currentView = this._searchResults[this._currentSearchResultIndex];
  726.  
  727. if (currentView.showingLastSearchResult()) {
  728. if (++this._currentSearchResultIndex >= this._searchResults.length)
  729. this._currentSearchResultIndex = 0;
  730. currentView = this._searchResults[this._currentSearchResultIndex];
  731. showFirstResult = true;
  732. }
  733.  
  734. WebInspector.searchController.updateCurrentMatchIndex(this._currentSearchResultIndex, this);
  735.  
  736. if (currentView !== this.visibleView) {
  737. this.showView(currentView);
  738. WebInspector.searchController.showSearchField();
  739. }
  740.  
  741. if (showFirstResult)
  742. currentView.jumpToFirstSearchResult();
  743. else
  744. currentView.jumpToNextSearchResult();
  745. },
  746.  
  747. jumpToPreviousSearchResult: function()
  748. {
  749. if (!this.showView || !this._searchResults || !this._searchResults.length)
  750. return;
  751.  
  752. var showLastResult = false;
  753.  
  754. this._currentSearchResultIndex = this._searchResults.indexOf(this.visibleView);
  755. if (this._currentSearchResultIndex === -1) {
  756. this._currentSearchResultIndex = 0;
  757. showLastResult = true;
  758. }
  759.  
  760. var currentView = this._searchResults[this._currentSearchResultIndex];
  761.  
  762. if (currentView.showingFirstSearchResult()) {
  763. if (--this._currentSearchResultIndex < 0)
  764. this._currentSearchResultIndex = (this._searchResults.length - 1);
  765. currentView = this._searchResults[this._currentSearchResultIndex];
  766. showLastResult = true;
  767. }
  768.  
  769. WebInspector.searchController.updateCurrentMatchIndex(this._currentSearchResultIndex, this);
  770.  
  771. if (currentView !== this.visibleView) {
  772. this.showView(currentView);
  773. WebInspector.searchController.showSearchField();
  774. }
  775.  
  776. if (showLastResult)
  777. currentView.jumpToLastSearchResult();
  778. else
  779. currentView.jumpToPreviousSearchResult();
  780. },
  781.  
  782. _searchableViews: function()
  783. {
  784. var views = [];
  785.  
  786. const visibleView = this.visibleView;
  787. if (visibleView && visibleView.performSearch)
  788. views.push(visibleView);
  789.  
  790. var profilesLength = this._profiles.length;
  791. for (var i = 0; i < profilesLength; ++i) {
  792. var profile = this._profiles[i];
  793. var view = profile.view();
  794. if (!view.performSearch || view === visibleView)
  795. continue;
  796. views.push(view);
  797. }
  798.  
  799. return views;
  800. },
  801.  
  802. searchMatchFound: function(view, matches)
  803. {
  804. view.profile._profilesTreeElement.searchMatches = matches;
  805. },
  806.  
  807. searchCanceled: function()
  808. {
  809. if (this._searchResults) {
  810. for (var i = 0; i < this._searchResults.length; ++i) {
  811. var view = this._searchResults[i];
  812. if (view.searchCanceled)
  813. view.searchCanceled();
  814. delete view.currentQuery;
  815. }
  816. }
  817.  
  818. WebInspector.Panel.prototype.searchCanceled.call(this);
  819.  
  820. if (this._currentSearchChunkIntervalIdentifier) {
  821. clearInterval(this._currentSearchChunkIntervalIdentifier);
  822. delete this._currentSearchChunkIntervalIdentifier;
  823. }
  824.  
  825. this._totalSearchMatches = 0;
  826. this._currentSearchResultIndex = 0;
  827. this._searchResults = [];
  828.  
  829. if (!this._profiles)
  830. return;
  831.  
  832. for (var i = 0; i < this._profiles.length; ++i) {
  833. var profile = this._profiles[i];
  834. profile._profilesTreeElement.searchMatches = 0;
  835. }
  836. },
  837.  
  838. _updateInterface: function()
  839. {
  840.  
  841. if (this._profilerEnabled) {
  842. this.enableToggleButton.title = WebInspector.UIString("Profiling enabled. Click to disable.");
  843. this.enableToggleButton.toggled = true;
  844. this.recordButton.visible = true;
  845. this.profileViewStatusBarItemsContainer.removeStyleClass("hidden");
  846. this.clearResultsButton.element.removeStyleClass("hidden");
  847. this.panelEnablerView.detach();
  848. } else {
  849. this.enableToggleButton.title = WebInspector.UIString("Profiling disabled. Click to enable.");
  850. this.enableToggleButton.toggled = false;
  851. this.recordButton.visible = false;
  852. this.profileViewStatusBarItemsContainer.addStyleClass("hidden");
  853. this.clearResultsButton.element.addStyleClass("hidden");
  854. this.panelEnablerView.show(this.element);
  855. }
  856. },
  857.  
  858. get profilerEnabled()
  859. {
  860. return this._profilerEnabled;
  861. },
  862.  
  863. enableProfiler: function()
  864. {
  865. if (this._profilerEnabled)
  866. return;
  867. this._toggleProfiling(this.panelEnablerView.alwaysEnabled);
  868. },
  869.  
  870. disableProfiler: function()
  871. {
  872. if (!this._profilerEnabled)
  873. return;
  874. this._toggleProfiling(this.panelEnablerView.alwaysEnabled);
  875. },
  876.  
  877. _toggleProfiling: function(optionalAlways)
  878. {
  879. if (this._profilerEnabled) {
  880. WebInspector.settings.profilerEnabled.set(false);
  881. ProfilerAgent.disable(this._profilerWasDisabled.bind(this));
  882. } else {
  883. WebInspector.settings.profilerEnabled.set(!!optionalAlways);
  884. ProfilerAgent.enable(this._profilerWasEnabled.bind(this));
  885. }
  886. },
  887.  
  888. _populateProfiles: function()
  889. {
  890. if (!this._profilerEnabled || this._profilesWereRequested)
  891. return;
  892.  
  893.  
  894. function populateCallback(error, profileHeaders) {
  895. if (error)
  896. return;
  897. profileHeaders.sort(function(a, b) { return a.uid - b.uid; });
  898. var profileHeadersLength = profileHeaders.length;
  899. for (var i = 0; i < profileHeadersLength; ++i) {
  900. var profileHeader = profileHeaders[i];
  901. var profileType = this.getProfileType(profileHeader.typeId);
  902. this.addProfileHeader(profileType.createProfile(profileHeader));
  903. }
  904. }
  905.  
  906. ProfilerAgent.getProfileHeaders(populateCallback.bind(this));
  907.  
  908. this._profilesWereRequested = true;
  909. },
  910.  
  911. sidebarResized: function(event)
  912. {
  913. this.onResize();
  914. },
  915.  
  916. onResize: function()
  917. {
  918. var minFloatingStatusBarItemsOffset = document.getElementById("panel-status-bar").totalOffsetLeft() + this._statusBarButtons.length * WebInspector.StatusBarButton.width;
  919. this.profileViewStatusBarItemsContainer.style.left = Math.max(minFloatingStatusBarItemsOffset, this.splitView.sidebarWidth()) + "px";
  920. },
  921.  
  922.  
  923. setRecordingProfile: function(profileType, isProfiling)
  924. {
  925. var profileTypeObject = this.getProfileType(profileType);
  926. profileTypeObject.setRecordingProfile(isProfiling);
  927. var temporaryProfile = this.findTemporaryProfile(profileType);
  928. if (!!temporaryProfile === isProfiling)
  929. return;
  930. if (!temporaryProfile)
  931. temporaryProfile = profileTypeObject.createTemporaryProfile();
  932. if (isProfiling)
  933. this.addProfileHeader(temporaryProfile);
  934. else
  935. this._removeTemporaryProfile(profileType);
  936. this.recordButton.toggled = isProfiling;
  937. this.recordButton.title = profileTypeObject.buttonTooltip;
  938. if (isProfiling)
  939. this._launcherView.profileStarted();
  940. else
  941. this._launcherView.profileFinished();
  942. },
  943.  
  944. takeHeapSnapshot: function()
  945. {
  946. var temporaryRecordingProfile = this.findTemporaryProfile(WebInspector.HeapSnapshotProfileType.TypeId);
  947. if (!temporaryRecordingProfile) {
  948. var profileTypeObject = this.getProfileType(WebInspector.HeapSnapshotProfileType.TypeId);
  949. this.addProfileHeader(profileTypeObject.createTemporaryProfile());
  950. }
  951. this._launcherView.profileStarted();
  952. function done() {
  953. this._launcherView.profileFinished();
  954. }
  955. ProfilerAgent.takeHeapSnapshot(done.bind(this));
  956. WebInspector.userMetrics.ProfilesHeapProfileTaken.record();
  957. },
  958.  
  959.  
  960. _reportHeapSnapshotProgress: function(done, total)
  961. {
  962. var temporaryProfile = this.findTemporaryProfile(WebInspector.HeapSnapshotProfileType.TypeId);
  963. if (temporaryProfile) {
  964. temporaryProfile.sidebarElement.subtitle = WebInspector.UIString("%.2f%", (done / total) * 100);
  965. temporaryProfile.sidebarElement.wait = true;
  966. if (done >= total)
  967. this._removeTemporaryProfile(WebInspector.HeapSnapshotProfileType.TypeId);
  968. }
  969. },
  970.  
  971.  
  972. appendApplicableItems: function(event, contextMenu, target)
  973. {
  974. if (WebInspector.inspectorView.currentPanel() !== this)
  975. return;
  976.  
  977. var object =   (target);
  978. var objectId = object.objectId;
  979. if (!objectId)
  980. return;
  981.  
  982. var heapProfiles = this.getProfiles(WebInspector.HeapSnapshotProfileType.TypeId);
  983. if (!heapProfiles.length)
  984. return;
  985.  
  986. function revealInView(viewName)
  987. {
  988. ProfilerAgent.getHeapObjectId(objectId, didReceiveHeapObjectId.bind(this, viewName));
  989. }
  990.  
  991. function didReceiveHeapObjectId(viewName, error, result)
  992. {
  993. if (WebInspector.inspectorView.currentPanel() !== this)
  994. return;
  995. if (!error)
  996. this.showObject(result, viewName);
  997. }
  998.  
  999. contextMenu.appendItem(WebInspector.UIString("Reveal in Dominators View"), revealInView.bind(this, "Dominators"));
  1000. contextMenu.appendItem(WebInspector.UIString("Reveal in Summary View"), revealInView.bind(this, "Summary"));
  1001. },
  1002.  
  1003. __proto__: WebInspector.Panel.prototype
  1004. }
  1005.  
  1006.  
  1007. WebInspector.ProfilerDispatcher = function(profiler)
  1008. {
  1009. this._profiler = profiler;
  1010. }
  1011.  
  1012. WebInspector.ProfilerDispatcher.prototype = {
  1013.  
  1014. addProfileHeader: function(profile)
  1015. {
  1016. var profileType = this._profiler.getProfileType(profile.typeId);
  1017. this._profiler.addProfileHeader(profileType.createProfile(profile));
  1018. },
  1019.  
  1020.  
  1021. addHeapSnapshotChunk: function(uid, chunk)
  1022. {
  1023. this._profiler._addHeapSnapshotChunk(uid, chunk);
  1024. },
  1025.  
  1026.  
  1027. finishHeapSnapshot: function(uid)
  1028. {
  1029. this._profiler._finishHeapSnapshot(uid);
  1030. },
  1031.  
  1032.  
  1033. setRecordingProfile: function(isProfiling)
  1034. {
  1035. this._profiler.setRecordingProfile(WebInspector.CPUProfileType.TypeId, isProfiling);
  1036. },
  1037.  
  1038.  
  1039. resetProfiles: function()
  1040. {
  1041. this._profiler._reset();
  1042. },
  1043.  
  1044.  
  1045. reportHeapSnapshotProgress: function(done, total)
  1046. {
  1047. this._profiler._reportHeapSnapshotProgress(done, total);
  1048. }
  1049. }
  1050.  
  1051.  
  1052. WebInspector.ProfileSidebarTreeElement = function(profile, titleFormat, className)
  1053. {
  1054. this.profile = profile;
  1055. this._titleFormat = titleFormat;
  1056.  
  1057. if (this.profile.title.startsWith(UserInitiatedProfileName))
  1058. this._profileNumber = this.profile.title.substring(UserInitiatedProfileName.length + 1);
  1059.  
  1060. WebInspector.SidebarTreeElement.call(this, className, "", "", profile, false);
  1061.  
  1062. this.refreshTitles();
  1063. }
  1064.  
  1065. WebInspector.ProfileSidebarTreeElement.prototype = {
  1066. onselect: function()
  1067. {
  1068. if (!this._suppressOnSelect)
  1069. this.treeOutline.panel.showProfile(this.profile);
  1070. },
  1071.  
  1072. ondelete: function()
  1073. {
  1074. this.treeOutline.panel._removeProfileHeader(this.profile);
  1075. return true;
  1076. },
  1077.  
  1078. get mainTitle()
  1079. {
  1080. if (this._mainTitle)
  1081. return this._mainTitle;
  1082. if (this.profile.title.startsWith(UserInitiatedProfileName))
  1083. return WebInspector.UIString(this._titleFormat, this._profileNumber);
  1084. return this.profile.title;
  1085. },
  1086.  
  1087. set mainTitle(x)
  1088. {
  1089. this._mainTitle = x;
  1090. this.refreshTitles();
  1091. },
  1092.  
  1093. set searchMatches(matches)
  1094. {
  1095. if (!matches) {
  1096. if (!this.bubbleElement)
  1097. return;
  1098. this.bubbleElement.removeStyleClass("search-matches");
  1099. this.bubbleText = "";
  1100. return;
  1101. }
  1102.  
  1103. this.bubbleText = matches;
  1104. this.bubbleElement.addStyleClass("search-matches");
  1105. },
  1106.  
  1107. handleContextMenuEvent: function(event)
  1108. {
  1109. var profile = this.profile;
  1110. var contextMenu = new WebInspector.ContextMenu(event);
  1111. var profilesPanel = WebInspector.ProfilesPanel._instance;
  1112.  
  1113. if (profile.canSaveToFile()) {
  1114. contextMenu.appendItem(WebInspector.UIString("Save Heap Snapshot\u2026"), profile.saveToFile.bind(profile));
  1115. contextMenu.appendItem(WebInspector.UIString("Load Heap Snapshot\u2026"), profilesPanel._fileSelectorElement.click.bind(profilesPanel._fileSelectorElement));
  1116. contextMenu.appendItem(WebInspector.UIString("Delete Heap Snapshot"), this.ondelete.bind(this));
  1117. } else {
  1118. contextMenu.appendItem(WebInspector.UIString("Load Heap Snapshot\u2026"), profilesPanel._fileSelectorElement.click.bind(profilesPanel._fileSelectorElement));
  1119. contextMenu.appendItem(WebInspector.UIString("Delete profile"), this.ondelete.bind(this));
  1120. }
  1121. contextMenu.show();
  1122. },
  1123.  
  1124. __proto__: WebInspector.SidebarTreeElement.prototype
  1125. }
  1126.  
  1127.  
  1128. WebInspector.ProfileGroupSidebarTreeElement = function(title, subtitle)
  1129. {
  1130. WebInspector.SidebarTreeElement.call(this, "profile-group-sidebar-tree-item", title, subtitle, null, true);
  1131. }
  1132.  
  1133. WebInspector.ProfileGroupSidebarTreeElement.prototype = {
  1134. onselect: function()
  1135. {
  1136. if (this.children.length > 0)
  1137. WebInspector.ProfilesPanel._instance.showProfile(this.children[this.children.length - 1].profile);
  1138. },
  1139.  
  1140. __proto__: WebInspector.SidebarTreeElement.prototype
  1141. }
  1142.  
  1143.  
  1144. WebInspector.ProfilesSidebarTreeElement = function(panel)
  1145. {
  1146. this._panel = panel;
  1147. this.small = false;
  1148.  
  1149. WebInspector.SidebarTreeElement.call(this, "profile-launcher-view-tree-item", WebInspector.UIString("Profiles"), "", null, false);
  1150. }
  1151.  
  1152. WebInspector.ProfilesSidebarTreeElement.prototype = {
  1153. onselect: function()
  1154. {
  1155. this._panel._showLauncherView();
  1156. },
  1157.  
  1158. get selectable()
  1159. {
  1160. return true;
  1161. },
  1162.  
  1163. __proto__: WebInspector.SidebarTreeElement.prototype
  1164. }
  1165.  
  1166.  
  1167.  
  1168.  
  1169. WebInspector.ProfileDataGridNode = function(profileView, profileNode, owningTree, hasChildren)
  1170. {
  1171. this.profileView = profileView;
  1172. this.profileNode = profileNode;
  1173.  
  1174. WebInspector.DataGridNode.call(this, null, hasChildren);
  1175.  
  1176. this.addEventListener("populate", this._populate, this);
  1177.  
  1178. this.tree = owningTree;
  1179.  
  1180. this.childrenByCallUID = {};
  1181. this.lastComparator = null;
  1182.  
  1183. this.callUID = profileNode.callUID;
  1184. this.selfTime = profileNode.selfTime;
  1185. this.totalTime = profileNode.totalTime;
  1186. this.functionName = profileNode.functionName;
  1187. this.numberOfCalls = profileNode.numberOfCalls;
  1188. this.url = profileNode.url;
  1189. }
  1190.  
  1191. WebInspector.ProfileDataGridNode.prototype = {
  1192. get data()
  1193. {
  1194. function formatMilliseconds(time)
  1195. {
  1196. return Number.secondsToString(time / 1000, !Capabilities.samplingCPUProfiler);
  1197. }
  1198.  
  1199. var data = {};
  1200.  
  1201. data["function"] = this.functionName;
  1202. data["calls"] = this.numberOfCalls;
  1203.  
  1204. if (this.profileView.showSelfTimeAsPercent.get())
  1205. data["self"] = WebInspector.UIString("%.2f%", this.selfPercent);
  1206. else
  1207. data["self"] = formatMilliseconds(this.selfTime);
  1208.  
  1209. if (this.profileView.showTotalTimeAsPercent.get())
  1210. data["total"] = WebInspector.UIString("%.2f%", this.totalPercent);
  1211. else
  1212. data["total"] = formatMilliseconds(this.totalTime);
  1213.  
  1214. if (this.profileView.showAverageTimeAsPercent.get())
  1215. data["average"] = WebInspector.UIString("%.2f%", this.averagePercent);
  1216. else
  1217. data["average"] = formatMilliseconds(this.averageTime);
  1218.  
  1219. return data;
  1220. },
  1221.  
  1222. createCell: function(columnIdentifier)
  1223. {
  1224. var cell = WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier);
  1225.  
  1226. if (columnIdentifier === "self" && this._searchMatchedSelfColumn)
  1227. cell.addStyleClass("highlight");
  1228. else if (columnIdentifier === "total" && this._searchMatchedTotalColumn)
  1229. cell.addStyleClass("highlight");
  1230. else if (columnIdentifier === "average" && this._searchMatchedAverageColumn)
  1231. cell.addStyleClass("highlight");
  1232. else if (columnIdentifier === "calls" && this._searchMatchedCallsColumn)
  1233. cell.addStyleClass("highlight");
  1234.  
  1235. if (columnIdentifier !== "function")
  1236. return cell;
  1237.  
  1238. if (this.profileNode._searchMatchedFunctionColumn)
  1239. cell.addStyleClass("highlight");
  1240.  
  1241. if (this.profileNode.url) {
  1242.  
  1243. var lineNumber = this.profileNode.lineNumber ? this.profileNode.lineNumber - 1 : 0;
  1244. var urlElement = this.profileView._linkifier.linkifyLocation(this.profileNode.url, lineNumber, 0, "profile-node-file");
  1245. urlElement.style.maxWidth = "75%";
  1246. cell.insertBefore(urlElement, cell.firstChild);
  1247. }
  1248.  
  1249. return cell;
  1250. },
  1251.  
  1252. select: function(supressSelectedEvent)
  1253. {
  1254. WebInspector.DataGridNode.prototype.select.call(this, supressSelectedEvent);
  1255. this.profileView._dataGridNodeSelected(this);
  1256. },
  1257.  
  1258. deselect: function(supressDeselectedEvent)
  1259. {
  1260. WebInspector.DataGridNode.prototype.deselect.call(this, supressDeselectedEvent);
  1261. this.profileView._dataGridNodeDeselected(this);
  1262. },
  1263.  
  1264. sort: function(  comparator,   force)
  1265. {
  1266. var gridNodeGroups = [[this]];
  1267.  
  1268. for (var gridNodeGroupIndex = 0; gridNodeGroupIndex < gridNodeGroups.length; ++gridNodeGroupIndex) {
  1269. var gridNodes = gridNodeGroups[gridNodeGroupIndex];
  1270. var count = gridNodes.length;
  1271.  
  1272. for (var index = 0; index < count; ++index) {
  1273. var gridNode = gridNodes[index];
  1274.  
  1275.  
  1276.  
  1277. if (!force && (!gridNode.expanded || gridNode.lastComparator === comparator)) {
  1278. if (gridNode.children.length)
  1279. gridNode.shouldRefreshChildren = true;
  1280. continue;
  1281. }
  1282.  
  1283. gridNode.lastComparator = comparator;
  1284.  
  1285. var children = gridNode.children;
  1286. var childCount = children.length;
  1287.  
  1288. if (childCount) {
  1289. children.sort(comparator);
  1290.  
  1291. for (var childIndex = 0; childIndex < childCount; ++childIndex)
  1292. children[childIndex]._recalculateSiblings(childIndex);
  1293.  
  1294. gridNodeGroups.push(children);
  1295. }
  1296. }
  1297. }
  1298. },
  1299.  
  1300. insertChild: function(  profileDataGridNode, index)
  1301. {
  1302. WebInspector.DataGridNode.prototype.insertChild.call(this, profileDataGridNode, index);
  1303.  
  1304. this.childrenByCallUID[profileDataGridNode.callUID] = profileDataGridNode;
  1305. },
  1306.  
  1307. removeChild: function(  profileDataGridNode)
  1308. {
  1309. WebInspector.DataGridNode.prototype.removeChild.call(this, profileDataGridNode);
  1310.  
  1311. delete this.childrenByCallUID[profileDataGridNode.callUID];
  1312. },
  1313.  
  1314. removeChildren: function(  profileDataGridNode)
  1315. {
  1316. WebInspector.DataGridNode.prototype.removeChildren.call(this);
  1317.  
  1318. this.childrenByCallUID = {};
  1319. },
  1320.  
  1321. findChild: function(  node)
  1322. {
  1323. if (!node)
  1324. return null;
  1325. return this.childrenByCallUID[node.callUID];
  1326. },
  1327.  
  1328. get averageTime()
  1329. {
  1330. return this.selfTime / Math.max(1, this.numberOfCalls);
  1331. },
  1332.  
  1333. get averagePercent()
  1334. {
  1335. return this.averageTime / this.tree.totalTime * 100.0;
  1336. },
  1337.  
  1338. get selfPercent()
  1339. {
  1340. return this.selfTime / this.tree.totalTime * 100.0;
  1341. },
  1342.  
  1343. get totalPercent()
  1344. {
  1345. return this.totalTime / this.tree.totalTime * 100.0;
  1346. },
  1347.  
  1348. get _parent()
  1349. {
  1350. return this.parent !== this.dataGrid ? this.parent : this.tree;
  1351. },
  1352.  
  1353. _populate: function()
  1354. {
  1355. this._sharedPopulate();
  1356.  
  1357. if (this._parent) {
  1358. var currentComparator = this._parent.lastComparator;
  1359.  
  1360. if (currentComparator)
  1361. this.sort(currentComparator, true);
  1362. }
  1363.  
  1364. if (this.removeEventListener)
  1365. this.removeEventListener("populate", this._populate, this);
  1366. },
  1367.  
  1368.  
  1369.  
  1370. _save: function()
  1371. {
  1372. if (this._savedChildren)
  1373. return;
  1374.  
  1375. this._savedSelfTime = this.selfTime;
  1376. this._savedTotalTime = this.totalTime;
  1377. this._savedNumberOfCalls = this.numberOfCalls;
  1378.  
  1379. this._savedChildren = this.children.slice();
  1380. },
  1381.  
  1382.  
  1383.  
  1384. _restore: function()
  1385. {
  1386. if (!this._savedChildren)
  1387. return;
  1388.  
  1389. this.selfTime = this._savedSelfTime;
  1390. this.totalTime = this._savedTotalTime;
  1391. this.numberOfCalls = this._savedNumberOfCalls;
  1392.  
  1393. this.removeChildren();
  1394.  
  1395. var children = this._savedChildren;
  1396. var count = children.length;
  1397.  
  1398. for (var index = 0; index < count; ++index) {
  1399. children[index]._restore();
  1400. this.appendChild(children[index]);
  1401. }
  1402. },
  1403.  
  1404. _merge: function(child, shouldAbsorb)
  1405. {
  1406. this.selfTime += child.selfTime;
  1407.  
  1408. if (!shouldAbsorb) {
  1409. this.totalTime += child.totalTime;
  1410. this.numberOfCalls += child.numberOfCalls;
  1411. }
  1412.  
  1413. var children = this.children.slice();
  1414.  
  1415. this.removeChildren();
  1416.  
  1417. var count = children.length;
  1418.  
  1419. for (var index = 0; index < count; ++index) {
  1420. if (!shouldAbsorb || children[index] !== child)
  1421. this.appendChild(children[index]);
  1422. }
  1423.  
  1424. children = child.children.slice();
  1425. count = children.length;
  1426.  
  1427. for (var index = 0; index < count; ++index) {
  1428. var orphanedChild = children[index],
  1429. existingChild = this.childrenByCallUID[orphanedChild.callUID];
  1430.  
  1431. if (existingChild)
  1432. existingChild._merge(orphanedChild, false);
  1433. else
  1434. this.appendChild(orphanedChild);
  1435. }
  1436. },
  1437.  
  1438. __proto__: WebInspector.DataGridNode.prototype
  1439. }
  1440.  
  1441.  
  1442. WebInspector.ProfileDataGridTree = function(profileView, profileNode)
  1443. {
  1444. this.tree = this;
  1445. this.children = [];
  1446.  
  1447. this.profileView = profileView;
  1448.  
  1449. this.totalTime = profileNode.totalTime;
  1450. this.lastComparator = null;
  1451.  
  1452. this.childrenByCallUID = {};
  1453. }
  1454.  
  1455. WebInspector.ProfileDataGridTree.prototype = {
  1456. get expanded()
  1457. {
  1458. return true;
  1459. },
  1460.  
  1461. appendChild: function(child)
  1462. {
  1463. this.insertChild(child, this.children.length);
  1464. },
  1465.  
  1466. insertChild: function(child, index)
  1467. {
  1468. this.children.splice(index, 0, child);
  1469. this.childrenByCallUID[child.callUID] = child;
  1470. },
  1471.  
  1472. removeChildren: function()
  1473. {
  1474. this.children = [];
  1475. this.childrenByCallUID = {};
  1476. },
  1477.  
  1478. findChild: WebInspector.ProfileDataGridNode.prototype.findChild,
  1479. sort: WebInspector.ProfileDataGridNode.prototype.sort,
  1480.  
  1481. _save: function()
  1482. {
  1483. if (this._savedChildren)
  1484. return;
  1485.  
  1486. this._savedTotalTime = this.totalTime;
  1487. this._savedChildren = this.children.slice();
  1488. },
  1489.  
  1490. restore: function()
  1491. {
  1492. if (!this._savedChildren)
  1493. return;
  1494.  
  1495. this.children = this._savedChildren;
  1496. this.totalTime = this._savedTotalTime;
  1497.  
  1498. var children = this.children;
  1499. var count = children.length;
  1500.  
  1501. for (var index = 0; index < count; ++index)
  1502. children[index]._restore();
  1503.  
  1504. this._savedChildren = null;
  1505. }
  1506. }
  1507.  
  1508. WebInspector.ProfileDataGridTree.propertyComparators = [{}, {}];
  1509.  
  1510. WebInspector.ProfileDataGridTree.propertyComparator = function(  property,   isAscending)
  1511. {
  1512. var comparator = WebInspector.ProfileDataGridTree.propertyComparators[(isAscending ? 1 : 0)][property];
  1513.  
  1514. if (!comparator) {
  1515. if (isAscending) {
  1516. comparator = function(lhs, rhs)
  1517. {
  1518. if (lhs[property] < rhs[property])
  1519. return -1;
  1520.  
  1521. if (lhs[property] > rhs[property])
  1522. return 1;
  1523.  
  1524. return 0;
  1525. }
  1526. } else {
  1527. comparator = function(lhs, rhs)
  1528. {
  1529. if (lhs[property] > rhs[property])
  1530. return -1;
  1531.  
  1532. if (lhs[property] < rhs[property])
  1533. return 1;
  1534.  
  1535. return 0;
  1536. }
  1537. }
  1538.  
  1539. WebInspector.ProfileDataGridTree.propertyComparators[(isAscending ? 1 : 0)][property] = comparator;
  1540. }
  1541.  
  1542. return comparator;
  1543. }
  1544. ;
  1545.  
  1546.  
  1547.  
  1548.  
  1549.  
  1550.  
  1551.  
  1552.  
  1553.  
  1554. WebInspector.BottomUpProfileDataGridNode = function(  profileView,   profileNode,   owningTree)
  1555. {
  1556. WebInspector.ProfileDataGridNode.call(this, profileView, profileNode, owningTree, this._willHaveChildren(profileNode));
  1557.  
  1558. this._remainingNodeInfos = [];
  1559. }
  1560.  
  1561. WebInspector.BottomUpProfileDataGridNode.prototype = {
  1562. _takePropertiesFromProfileDataGridNode: function(  profileDataGridNode)
  1563. {
  1564. this._save();
  1565.  
  1566. this.selfTime = profileDataGridNode.selfTime;
  1567. this.totalTime = profileDataGridNode.totalTime;
  1568. this.numberOfCalls = profileDataGridNode.numberOfCalls;
  1569. },
  1570.  
  1571.  
  1572. _keepOnlyChild: function(  child)
  1573. {
  1574. this._save();
  1575.  
  1576. this.removeChildren();
  1577. this.appendChild(child);
  1578. },
  1579.  
  1580. _exclude: function(aCallUID)
  1581. {
  1582. if (this._remainingNodeInfos)
  1583. this._populate();
  1584.  
  1585. this._save();
  1586.  
  1587. var children = this.children;
  1588. var index = this.children.length;
  1589.  
  1590. while (index--)
  1591. children[index]._exclude(aCallUID);
  1592.  
  1593. var child = this.childrenByCallUID[aCallUID];
  1594.  
  1595. if (child)
  1596. this._merge(child, true);
  1597. },
  1598.  
  1599. _restore: function()
  1600. {
  1601. WebInspector.ProfileDataGridNode.prototype._restore();
  1602.  
  1603. if (!this.children.length)
  1604. this.hasChildren = this._willHaveChildren(this.profileNode);
  1605. },
  1606.  
  1607. _merge: function(  child,   shouldAbsorb)
  1608. {
  1609. this.selfTime -= child.selfTime;
  1610.  
  1611. WebInspector.ProfileDataGridNode.prototype._merge.call(this, child, shouldAbsorb);
  1612. },
  1613.  
  1614. _sharedPopulate: function()
  1615. {
  1616. var remainingNodeInfos = this._remainingNodeInfos;
  1617. var count = remainingNodeInfos.length;
  1618.  
  1619. for (var index = 0; index < count; ++index) {
  1620. var nodeInfo = remainingNodeInfos[index];
  1621. var ancestor = nodeInfo.ancestor;
  1622. var focusNode = nodeInfo.focusNode;
  1623. var child = this.findChild(ancestor);
  1624.  
  1625.  
  1626. if (child) {
  1627. var totalTimeAccountedFor = nodeInfo.totalTimeAccountedFor;
  1628.  
  1629. child.selfTime += focusNode.selfTime;
  1630. child.numberOfCalls += focusNode.numberOfCalls;
  1631.  
  1632. if (!totalTimeAccountedFor)
  1633. child.totalTime += focusNode.totalTime;
  1634. } else {
  1635.  
  1636.  
  1637. child = new WebInspector.BottomUpProfileDataGridNode(this.profileView, ancestor, this.tree);
  1638.  
  1639. if (ancestor !== focusNode) {
  1640.  
  1641. child.selfTime = focusNode.selfTime;
  1642. child.totalTime = focusNode.totalTime;
  1643. child.numberOfCalls = focusNode.numberOfCalls;
  1644. }
  1645.  
  1646. this.appendChild(child);
  1647. }
  1648.  
  1649. var parent = ancestor.parent;
  1650. if (parent && parent.parent) {
  1651. nodeInfo.ancestor = parent;
  1652. child._remainingNodeInfos.push(nodeInfo);
  1653. }
  1654. }
  1655.  
  1656. delete this._remainingNodeInfos;
  1657. },
  1658.  
  1659. _willHaveChildren: function(profileNode)
  1660. {
  1661.  
  1662.  
  1663. return !!(profileNode.parent && profileNode.parent.parent);
  1664. },
  1665.  
  1666. __proto__: WebInspector.ProfileDataGridNode.prototype
  1667. }
  1668.  
  1669.  
  1670. WebInspector.BottomUpProfileDataGridTree = function(  aProfileView,   aProfileNode)
  1671. {
  1672. WebInspector.ProfileDataGridTree.call(this, aProfileView, aProfileNode);
  1673.  
  1674.  
  1675. var profileNodeUIDs = 0;
  1676. var profileNodeGroups = [[], [aProfileNode]];
  1677. var visitedProfileNodesForCallUID = {};
  1678.  
  1679. this._remainingNodeInfos = [];
  1680.  
  1681. for (var profileNodeGroupIndex = 0; profileNodeGroupIndex < profileNodeGroups.length; ++profileNodeGroupIndex) {
  1682. var parentProfileNodes = profileNodeGroups[profileNodeGroupIndex];
  1683. var profileNodes = profileNodeGroups[++profileNodeGroupIndex];
  1684. var count = profileNodes.length;
  1685.  
  1686. for (var index = 0; index < count; ++index) {
  1687. var profileNode = profileNodes[index];
  1688.  
  1689. if (!profileNode.UID)
  1690. profileNode.UID = ++profileNodeUIDs;
  1691.  
  1692. if (profileNode.head && profileNode !== profileNode.head) {
  1693.  
  1694. var visitedNodes = visitedProfileNodesForCallUID[profileNode.callUID];
  1695. var totalTimeAccountedFor = false;
  1696.  
  1697. if (!visitedNodes) {
  1698. visitedNodes = {}
  1699. visitedProfileNodesForCallUID[profileNode.callUID] = visitedNodes;
  1700. } else {
  1701.  
  1702.  
  1703. var parentCount = parentProfileNodes.length;
  1704. for (var parentIndex = 0; parentIndex < parentCount; ++parentIndex) {
  1705. if (visitedNodes[parentProfileNodes[parentIndex].UID]) {
  1706. totalTimeAccountedFor = true;
  1707. break;
  1708. }
  1709. }
  1710. }
  1711.  
  1712. visitedNodes[profileNode.UID] = true;
  1713.  
  1714. this._remainingNodeInfos.push({ ancestor:profileNode, focusNode:profileNode, totalTimeAccountedFor:totalTimeAccountedFor });
  1715. }
  1716.  
  1717. var children = profileNode.children;
  1718. if (children.length) {
  1719. profileNodeGroups.push(parentProfileNodes.concat([profileNode]))
  1720. profileNodeGroups.push(children);
  1721. }
  1722. }
  1723. }
  1724.  
  1725.  
  1726. var any =  this;
  1727. var node =  any;
  1728. WebInspector.BottomUpProfileDataGridNode.prototype._populate.call(node);
  1729.  
  1730. return this;
  1731. }
  1732.  
  1733. WebInspector.BottomUpProfileDataGridTree.prototype = {
  1734.  
  1735. focus: function(  profileDataGridNode)
  1736. {
  1737. if (!profileDataGridNode)
  1738. return;
  1739.  
  1740. this._save();
  1741.  
  1742. var currentNode = profileDataGridNode;
  1743. var focusNode = profileDataGridNode;
  1744.  
  1745. while (currentNode.parent && (currentNode instanceof WebInspector.ProfileDataGridNode)) {
  1746. currentNode._takePropertiesFromProfileDataGridNode(profileDataGridNode);
  1747.  
  1748. focusNode = currentNode;
  1749. currentNode = currentNode.parent;
  1750.  
  1751. if (currentNode instanceof WebInspector.ProfileDataGridNode)
  1752. currentNode._keepOnlyChild(focusNode);
  1753. }
  1754.  
  1755. this.children = [focusNode];
  1756. this.totalTime = profileDataGridNode.totalTime;
  1757. },
  1758.  
  1759. exclude: function(  profileDataGridNode)
  1760. {
  1761. if (!profileDataGridNode)
  1762. return;
  1763.  
  1764. this._save();
  1765.  
  1766. var excludedCallUID = profileDataGridNode.callUID;
  1767. var excludedTopLevelChild = this.childrenByCallUID[excludedCallUID];
  1768.  
  1769.  
  1770.  
  1771. if (excludedTopLevelChild)
  1772. this.children.remove(excludedTopLevelChild);
  1773.  
  1774. var children = this.children;
  1775. var count = children.length;
  1776.  
  1777. for (var index = 0; index < count; ++index)
  1778. children[index]._exclude(excludedCallUID);
  1779.  
  1780. if (this.lastComparator)
  1781. this.sort(this.lastComparator, true);
  1782. },
  1783.  
  1784. _sharedPopulate: WebInspector.BottomUpProfileDataGridNode.prototype._sharedPopulate,
  1785.  
  1786. __proto__: WebInspector.ProfileDataGridTree.prototype
  1787. }
  1788. ;
  1789.  
  1790.  
  1791.  
  1792. WebInspector.CPUProfileView = function(profile)
  1793. {
  1794. WebInspector.View.call(this);
  1795.  
  1796. this.element.addStyleClass("profile-view");
  1797.  
  1798. this.showSelfTimeAsPercent = WebInspector.settings.createSetting("cpuProfilerShowSelfTimeAsPercent", true);
  1799. this.showTotalTimeAsPercent = WebInspector.settings.createSetting("cpuProfilerShowTotalTimeAsPercent", true);
  1800. this.showAverageTimeAsPercent = WebInspector.settings.createSetting("cpuProfilerShowAverageTimeAsPercent", true);
  1801. this._viewType = WebInspector.settings.createSetting("cpuProfilerView", WebInspector.CPUProfileView._TypeHeavy);
  1802.  
  1803. var columns = { "self": { title: WebInspector.UIString("Self"), width: "72px", sort: "descending", sortable: true },
  1804. "total": { title: WebInspector.UIString("Total"), width: "72px", sortable: true },
  1805. "average": { title: WebInspector.UIString("Average"), width: "72px", sortable: true },
  1806. "calls": { title: WebInspector.UIString("Calls"), width: "54px", sortable: true },
  1807. "function": { title: WebInspector.UIString("Function"), disclosure: true, sortable: true } };
  1808.  
  1809. if (Capabilities.samplingCPUProfiler) {
  1810. delete columns.average;
  1811. delete columns.calls;
  1812. }
  1813.  
  1814. this.dataGrid = new WebInspector.DataGrid(columns);
  1815. this.dataGrid.addEventListener("sorting changed", this._sortProfile, this);
  1816. this.dataGrid.element.addEventListener("mousedown", this._mouseDownInDataGrid.bind(this), true);
  1817. this.dataGrid.show(this.element);
  1818.  
  1819. this.viewSelectComboBox = new WebInspector.StatusBarComboBox(this._changeView.bind(this));
  1820.  
  1821. var heavyViewOption = document.createElement("option");
  1822. heavyViewOption.label = WebInspector.UIString("Heavy (Bottom Up)");
  1823. heavyViewOption.value = WebInspector.CPUProfileView._TypeHeavy;
  1824. var treeViewOption = document.createElement("option");
  1825. treeViewOption.label = WebInspector.UIString("Tree (Top Down)");
  1826. treeViewOption.value = WebInspector.CPUProfileView._TypeTree;
  1827.  
  1828. this.viewSelectComboBox.addOption(heavyViewOption);
  1829. this.viewSelectComboBox.addOption(treeViewOption);
  1830. this.viewSelectComboBox.select(this._viewType.get() === WebInspector.CPUProfileView._TypeHeavy ? heavyViewOption : treeViewOption);
  1831.  
  1832. this.percentButton = new WebInspector.StatusBarButton("", "percent-time-status-bar-item");
  1833. this.percentButton.addEventListener("click", this._percentClicked, this);
  1834.  
  1835. this.focusButton = new WebInspector.StatusBarButton(WebInspector.UIString("Focus selected function."), "focus-profile-node-status-bar-item");
  1836. this.focusButton.disabled = true;
  1837. this.focusButton.addEventListener("click", this._focusClicked, this);
  1838.  
  1839. this.excludeButton = new WebInspector.StatusBarButton(WebInspector.UIString("Exclude selected function."), "exclude-profile-node-status-bar-item");
  1840. this.excludeButton.disabled = true;
  1841. this.excludeButton.addEventListener("click", this._excludeClicked, this);
  1842.  
  1843. this.resetButton = new WebInspector.StatusBarButton(WebInspector.UIString("Restore all functions."), "reset-profile-status-bar-item");
  1844. this.resetButton.visible = false;
  1845. this.resetButton.addEventListener("click", this._resetClicked, this);
  1846.  
  1847. this.profile = profile;
  1848.  
  1849. function profileCallback(error, profile)
  1850. {
  1851. if (error)
  1852. return;
  1853.  
  1854. if (!profile.head) {
  1855.  
  1856. return;
  1857. }
  1858. this.profile.head = profile.head;
  1859. this._assignParentsInProfile();
  1860. this._changeView();
  1861. this._updatePercentButton();
  1862. }
  1863.  
  1864. this._linkifier = new WebInspector.Linkifier(new WebInspector.Linkifier.DefaultFormatter(30));
  1865.  
  1866. ProfilerAgent.getProfile(this.profile.profileType().id, this.profile.uid, profileCallback.bind(this));
  1867. }
  1868.  
  1869. WebInspector.CPUProfileView._TypeTree = "Tree";
  1870. WebInspector.CPUProfileView._TypeHeavy = "Heavy";
  1871.  
  1872. WebInspector.CPUProfileView.prototype = {
  1873. get statusBarItems()
  1874. {
  1875. return [this.viewSelectComboBox.element, this.percentButton.element, this.focusButton.element, this.excludeButton.element, this.resetButton.element];
  1876. },
  1877.  
  1878. get bottomUpProfileDataGridTree()
  1879. {
  1880. if (!this._bottomUpProfileDataGridTree) {
  1881. if (this.profile.bottomUpHead)
  1882. this._bottomUpProfileDataGridTree = new WebInspector.TopDownProfileDataGridTree(this, this.profile.bottomUpHead);
  1883. else
  1884. this._bottomUpProfileDataGridTree = new WebInspector.BottomUpProfileDataGridTree(this, this.profile.head);
  1885. }
  1886. return this._bottomUpProfileDataGridTree;
  1887. },
  1888.  
  1889. get topDownProfileDataGridTree()
  1890. {
  1891. if (!this._topDownProfileDataGridTree)
  1892. this._topDownProfileDataGridTree = new WebInspector.TopDownProfileDataGridTree(this, this.profile.head);
  1893. return this._topDownProfileDataGridTree;
  1894. },
  1895.  
  1896. get currentTree()
  1897. {
  1898. return this._currentTree;
  1899. },
  1900.  
  1901. set currentTree(tree)
  1902. {
  1903. this._currentTree = tree;
  1904. this.refresh();
  1905. },
  1906.  
  1907. willHide: function()
  1908. {
  1909. this._currentSearchResultIndex = -1;
  1910. },
  1911.  
  1912. refresh: function()
  1913. {
  1914. var selectedProfileNode = this.dataGrid.selectedNode ? this.dataGrid.selectedNode.profileNode : null;
  1915.  
  1916. this.dataGrid.rootNode().removeChildren();
  1917.  
  1918. var children = this.profileDataGridTree.children;
  1919. var count = children.length;
  1920.  
  1921. for (var index = 0; index < count; ++index)
  1922. this.dataGrid.rootNode().appendChild(children[index]);
  1923.  
  1924. if (selectedProfileNode)
  1925. selectedProfileNode.selected = true;
  1926. },
  1927.  
  1928. refreshVisibleData: function()
  1929. {
  1930. var child = this.dataGrid.rootNode().children[0];
  1931. while (child) {
  1932. child.refresh();
  1933. child = child.traverseNextNode(false, null, true);
  1934. }
  1935. },
  1936.  
  1937. refreshShowAsPercents: function()
  1938. {
  1939. this._updatePercentButton();
  1940. this.refreshVisibleData();
  1941. },
  1942.  
  1943. searchCanceled: function()
  1944. {
  1945. if (this._searchResults) {
  1946. for (var i = 0; i < this._searchResults.length; ++i) {
  1947. var profileNode = this._searchResults[i].profileNode;
  1948.  
  1949. delete profileNode._searchMatchedSelfColumn;
  1950. delete profileNode._searchMatchedTotalColumn;
  1951. delete profileNode._searchMatchedCallsColumn;
  1952. delete profileNode._searchMatchedFunctionColumn;
  1953.  
  1954. profileNode.refresh();
  1955. }
  1956. }
  1957.  
  1958. delete this._searchFinishedCallback;
  1959. this._currentSearchResultIndex = -1;
  1960. this._searchResults = [];
  1961. },
  1962.  
  1963. performSearch: function(query, finishedCallback)
  1964. {
  1965.  
  1966. this.searchCanceled();
  1967.  
  1968. query = query.trim();
  1969.  
  1970. if (!query.length)
  1971. return;
  1972.  
  1973. this._searchFinishedCallback = finishedCallback;
  1974.  
  1975. var greaterThan = (query.startsWith(">"));
  1976. var lessThan = (query.startsWith("<"));
  1977. var equalTo = (query.startsWith("=") || ((greaterThan || lessThan) && query.indexOf("=") === 1));
  1978. var percentUnits = (query.lastIndexOf("%") === (query.length - 1));
  1979. var millisecondsUnits = (query.length > 2 && query.lastIndexOf("ms") === (query.length - 2));
  1980. var secondsUnits = (!millisecondsUnits && query.lastIndexOf("s") === (query.length - 1));
  1981.  
  1982. var queryNumber = parseFloat(query);
  1983. if (greaterThan || lessThan || equalTo) {
  1984. if (equalTo && (greaterThan || lessThan))
  1985. queryNumber = parseFloat(query.substring(2));
  1986. else
  1987. queryNumber = parseFloat(query.substring(1));
  1988. }
  1989.  
  1990. var queryNumberMilliseconds = (secondsUnits ? (queryNumber * 1000) : queryNumber);
  1991.  
  1992.  
  1993. if (!isNaN(queryNumber) && !(greaterThan || lessThan))
  1994. equalTo = true;
  1995.  
  1996. function matchesQuery(  profileDataGridNode)
  1997. {
  1998. delete profileDataGridNode._searchMatchedSelfColumn;
  1999. delete profileDataGridNode._searchMatchedTotalColumn;
  2000. delete profileDataGridNode._searchMatchedAverageColumn;
  2001. delete profileDataGridNode._searchMatchedCallsColumn;
  2002. delete profileDataGridNode._searchMatchedFunctionColumn;
  2003.  
  2004. if (percentUnits) {
  2005. if (lessThan) {
  2006. if (profileDataGridNode.selfPercent < queryNumber)
  2007. profileDataGridNode._searchMatchedSelfColumn = true;
  2008. if (profileDataGridNode.totalPercent < queryNumber)
  2009. profileDataGridNode._searchMatchedTotalColumn = true;
  2010. if (profileDataGridNode.averagePercent < queryNumberMilliseconds)
  2011. profileDataGridNode._searchMatchedAverageColumn = true;
  2012. } else if (greaterThan) {
  2013. if (profileDataGridNode.selfPercent > queryNumber)
  2014. profileDataGridNode._searchMatchedSelfColumn = true;
  2015. if (profileDataGridNode.totalPercent > queryNumber)
  2016. profileDataGridNode._searchMatchedTotalColumn = true;
  2017. if (profileDataGridNode.averagePercent < queryNumberMilliseconds)
  2018. profileDataGridNode._searchMatchedAverageColumn = true;
  2019. }
  2020.  
  2021. if (equalTo) {
  2022. if (profileDataGridNode.selfPercent == queryNumber)
  2023. profileDataGridNode._searchMatchedSelfColumn = true;
  2024. if (profileDataGridNode.totalPercent == queryNumber)
  2025. profileDataGridNode._searchMatchedTotalColumn = true;
  2026. if (profileDataGridNode.averagePercent < queryNumberMilliseconds)
  2027. profileDataGridNode._searchMatchedAverageColumn = true;
  2028. }
  2029. } else if (millisecondsUnits || secondsUnits) {
  2030. if (lessThan) {
  2031. if (profileDataGridNode.selfTime < queryNumberMilliseconds)
  2032. profileDataGridNode._searchMatchedSelfColumn = true;
  2033. if (profileDataGridNode.totalTime < queryNumberMilliseconds)
  2034. profileDataGridNode._searchMatchedTotalColumn = true;
  2035. if (profileDataGridNode.averageTime < queryNumberMilliseconds)
  2036. profileDataGridNode._searchMatchedAverageColumn = true;
  2037. } else if (greaterThan) {
  2038. if (profileDataGridNode.selfTime > queryNumberMilliseconds)
  2039. profileDataGridNode._searchMatchedSelfColumn = true;
  2040. if (profileDataGridNode.totalTime > queryNumberMilliseconds)
  2041. profileDataGridNode._searchMatchedTotalColumn = true;
  2042. if (profileDataGridNode.averageTime > queryNumberMilliseconds)
  2043. profileDataGridNode._searchMatchedAverageColumn = true;
  2044. }
  2045.  
  2046. if (equalTo) {
  2047. if (profileDataGridNode.selfTime == queryNumberMilliseconds)
  2048. profileDataGridNode._searchMatchedSelfColumn = true;
  2049. if (profileDataGridNode.totalTime == queryNumberMilliseconds)
  2050. profileDataGridNode._searchMatchedTotalColumn = true;
  2051. if (profileDataGridNode.averageTime == queryNumberMilliseconds)
  2052. profileDataGridNode._searchMatchedAverageColumn = true;
  2053. }
  2054. } else {
  2055. if (equalTo && profileDataGridNode.numberOfCalls == queryNumber)
  2056. profileDataGridNode._searchMatchedCallsColumn = true;
  2057. if (greaterThan && profileDataGridNode.numberOfCalls > queryNumber)
  2058. profileDataGridNode._searchMatchedCallsColumn = true;
  2059. if (lessThan && profileDataGridNode.numberOfCalls < queryNumber)
  2060. profileDataGridNode._searchMatchedCallsColumn = true;
  2061. }
  2062.  
  2063. if (profileDataGridNode.functionName.hasSubstring(query, true) || profileDataGridNode.url.hasSubstring(query, true))
  2064. profileDataGridNode._searchMatchedFunctionColumn = true;
  2065.  
  2066. if (profileDataGridNode._searchMatchedSelfColumn ||
  2067. profileDataGridNode._searchMatchedTotalColumn ||
  2068. profileDataGridNode._searchMatchedAverageColumn ||
  2069. profileDataGridNode._searchMatchedCallsColumn ||
  2070. profileDataGridNode._searchMatchedFunctionColumn)
  2071. {
  2072. profileDataGridNode.refresh();
  2073. return true;
  2074. }
  2075.  
  2076. return false;
  2077. }
  2078.  
  2079. var current = this.profileDataGridTree.children[0];
  2080.  
  2081. while (current) {
  2082. if (matchesQuery(current)) {
  2083. this._searchResults.push({ profileNode: current });
  2084. }
  2085.  
  2086. current = current.traverseNextNode(false, null, false);
  2087. }
  2088.  
  2089. finishedCallback(this, this._searchResults.length);
  2090. },
  2091.  
  2092. jumpToFirstSearchResult: function()
  2093. {
  2094. if (!this._searchResults || !this._searchResults.length)
  2095. return;
  2096. this._currentSearchResultIndex = 0;
  2097. this._jumpToSearchResult(this._currentSearchResultIndex);
  2098. },
  2099.  
  2100. jumpToLastSearchResult: function()
  2101. {
  2102. if (!this._searchResults || !this._searchResults.length)
  2103. return;
  2104. this._currentSearchResultIndex = (this._searchResults.length - 1);
  2105. this._jumpToSearchResult(this._currentSearchResultIndex);
  2106. },
  2107.  
  2108. jumpToNextSearchResult: function()
  2109. {
  2110. if (!this._searchResults || !this._searchResults.length)
  2111. return;
  2112. if (++this._currentSearchResultIndex >= this._searchResults.length)
  2113. this._currentSearchResultIndex = 0;
  2114. this._jumpToSearchResult(this._currentSearchResultIndex);
  2115. },
  2116.  
  2117. jumpToPreviousSearchResult: function()
  2118. {
  2119. if (!this._searchResults || !this._searchResults.length)
  2120. return;
  2121. if (--this._currentSearchResultIndex < 0)
  2122. this._currentSearchResultIndex = (this._searchResults.length - 1);
  2123. this._jumpToSearchResult(this._currentSearchResultIndex);
  2124. },
  2125.  
  2126. showingFirstSearchResult: function()
  2127. {
  2128. return (this._currentSearchResultIndex === 0);
  2129. },
  2130.  
  2131. showingLastSearchResult: function()
  2132. {
  2133. return (this._searchResults && this._currentSearchResultIndex === (this._searchResults.length - 1));
  2134. },
  2135.  
  2136. _jumpToSearchResult: function(index)
  2137. {
  2138. var searchResult = this._searchResults[index];
  2139. if (!searchResult)
  2140. return;
  2141.  
  2142. var profileNode = searchResult.profileNode;
  2143. profileNode.revealAndSelect();
  2144. },
  2145.  
  2146. _changeView: function()
  2147. {
  2148. if (!this.profile)
  2149. return;
  2150.  
  2151. switch (this.viewSelectComboBox.selectedOption().value) {
  2152. case WebInspector.CPUProfileView._TypeTree:
  2153. this.profileDataGridTree = this.topDownProfileDataGridTree;
  2154. this._sortProfile();
  2155. this._viewType.set(WebInspector.CPUProfileView._TypeTree);
  2156. break;
  2157. case WebInspector.CPUProfileView._TypeHeavy:
  2158. this.profileDataGridTree = this.bottomUpProfileDataGridTree;
  2159. this._sortProfile();
  2160. this._viewType.set(WebInspector.CPUProfileView._TypeHeavy);
  2161. }
  2162.  
  2163. if (!this.currentQuery || !this._searchFinishedCallback || !this._searchResults)
  2164. return;
  2165.  
  2166.  
  2167.  
  2168.  
  2169. this._searchFinishedCallback(this, -this._searchResults.length);
  2170. this.performSearch(this.currentQuery, this._searchFinishedCallback);
  2171. },
  2172.  
  2173. _percentClicked: function(event)
  2174. {
  2175. var currentState = this.showSelfTimeAsPercent.get() && this.showTotalTimeAsPercent.get() && this.showAverageTimeAsPercent.get();
  2176. this.showSelfTimeAsPercent.set(!currentState);
  2177. this.showTotalTimeAsPercent.set(!currentState);
  2178. this.showAverageTimeAsPercent.set(!currentState);
  2179. this.refreshShowAsPercents();
  2180. },
  2181.  
  2182. _updatePercentButton: function()
  2183. {
  2184. if (this.showSelfTimeAsPercent.get() && this.showTotalTimeAsPercent.get() && this.showAverageTimeAsPercent.get()) {
  2185. this.percentButton.title = WebInspector.UIString("Show absolute total and self times.");
  2186. this.percentButton.toggled = true;
  2187. } else {
  2188. this.percentButton.title = WebInspector.UIString("Show total and self times as percentages.");
  2189. this.percentButton.toggled = false;
  2190. }
  2191. },
  2192.  
  2193. _focusClicked: function(event)
  2194. {
  2195. if (!this.dataGrid.selectedNode)
  2196. return;
  2197.  
  2198. this.resetButton.visible = true;
  2199. this.profileDataGridTree.focus(this.dataGrid.selectedNode);
  2200. this.refresh();
  2201. this.refreshVisibleData();
  2202. },
  2203.  
  2204. _excludeClicked: function(event)
  2205. {
  2206. var selectedNode = this.dataGrid.selectedNode
  2207.  
  2208. if (!selectedNode)
  2209. return;
  2210.  
  2211. selectedNode.deselect();
  2212.  
  2213. this.resetButton.visible = true;
  2214. this.profileDataGridTree.exclude(selectedNode);
  2215. this.refresh();
  2216. this.refreshVisibleData();
  2217. },
  2218.  
  2219. _resetClicked: function(event)
  2220. {
  2221. this.resetButton.visible = false;
  2222. this.profileDataGridTree.restore();
  2223. this._linkifier.reset();
  2224. this.refresh();
  2225. this.refreshVisibleData();
  2226. },
  2227.  
  2228. _dataGridNodeSelected: function(node)
  2229. {
  2230. this.focusButton.disabled = false;
  2231. this.excludeButton.disabled = false;
  2232. },
  2233.  
  2234. _dataGridNodeDeselected: function(node)
  2235. {
  2236. this.focusButton.disabled = true;
  2237. this.excludeButton.disabled = true;
  2238. },
  2239.  
  2240. _sortProfile: function()
  2241. {
  2242. var sortAscending = this.dataGrid.sortOrder === "ascending";
  2243. var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier;
  2244. var sortProperty = {
  2245. "average": "averageTime",
  2246. "self": "selfTime",
  2247. "total": "totalTime",
  2248. "calls": "numberOfCalls",
  2249. "function": "functionName"
  2250. }[sortColumnIdentifier];
  2251.  
  2252. this.profileDataGridTree.sort(WebInspector.ProfileDataGridTree.propertyComparator(sortProperty, sortAscending));
  2253.  
  2254. this.refresh();
  2255. },
  2256.  
  2257. _mouseDownInDataGrid: function(event)
  2258. {
  2259. if (event.detail < 2)
  2260. return;
  2261.  
  2262. var cell = event.target.enclosingNodeOrSelfWithNodeName("td");
  2263. if (!cell || (!cell.hasStyleClass("total-column") && !cell.hasStyleClass("self-column") && !cell.hasStyleClass("average-column")))
  2264. return;
  2265.  
  2266. if (cell.hasStyleClass("total-column"))
  2267. this.showTotalTimeAsPercent.set(!this.showTotalTimeAsPercent.get());
  2268. else if (cell.hasStyleClass("self-column"))
  2269. this.showSelfTimeAsPercent.set(!this.showSelfTimeAsPercent.get());
  2270. else if (cell.hasStyleClass("average-column"))
  2271. this.showAverageTimeAsPercent.set(!this.showAverageTimeAsPercent.get());
  2272.  
  2273. this.refreshShowAsPercents();
  2274.  
  2275. event.consume(true);
  2276. },
  2277.  
  2278. _assignParentsInProfile: function()
  2279. {
  2280. var head = this.profile.head;
  2281. head.parent = null;
  2282. head.head = null;
  2283. var nodesToTraverse = [ { parent: head, children: head.children } ];
  2284. while (nodesToTraverse.length > 0) {
  2285. var pair = nodesToTraverse.shift();
  2286. var parent = pair.parent;
  2287. var children = pair.children;
  2288. var length = children.length;
  2289. for (var i = 0; i < length; ++i) {
  2290. children[i].head = head;
  2291. children[i].parent = parent;
  2292. if (children[i].children.length > 0)
  2293. nodesToTraverse.push({ parent: children[i], children: children[i].children });
  2294. }
  2295. }
  2296. },
  2297.  
  2298. __proto__: WebInspector.View.prototype
  2299. }
  2300.  
  2301.  
  2302. WebInspector.CPUProfileType = function()
  2303. {
  2304. WebInspector.ProfileType.call(this, WebInspector.CPUProfileType.TypeId, WebInspector.UIString("Collect JavaScript CPU Profile"));
  2305. this._recording = false;
  2306. WebInspector.CPUProfileType.instance = this;
  2307. }
  2308.  
  2309. WebInspector.CPUProfileType.TypeId = "CPU";
  2310.  
  2311. WebInspector.CPUProfileType.prototype = {
  2312. get buttonTooltip()
  2313. {
  2314. return this._recording ? WebInspector.UIString("Stop CPU profiling.") : WebInspector.UIString("Start CPU profiling.");
  2315. },
  2316.  
  2317.  
  2318. buttonClicked: function()
  2319. {
  2320. if (this._recording) {
  2321. this.stopRecordingProfile();
  2322. return false;
  2323. } else {
  2324. this.startRecordingProfile();
  2325. return true;
  2326. }
  2327. },
  2328.  
  2329. get treeItemTitle()
  2330. {
  2331. return WebInspector.UIString("CPU PROFILES");
  2332. },
  2333.  
  2334. get description()
  2335. {
  2336. return WebInspector.UIString("CPU profiles show where the execution time is spent in your page's JavaScript functions.");
  2337. },
  2338.  
  2339. isRecordingProfile: function()
  2340. {
  2341. return this._recording;
  2342. },
  2343.  
  2344. startRecordingProfile: function()
  2345. {
  2346. this._recording = true;
  2347. WebInspector.userMetrics.ProfilesCPUProfileTaken.record();
  2348. ProfilerAgent.start();
  2349. },
  2350.  
  2351. stopRecordingProfile: function()
  2352. {
  2353. this._recording = false;
  2354. ProfilerAgent.stop();
  2355. },
  2356.  
  2357. setRecordingProfile: function(isProfiling)
  2358. {
  2359. this._recording = isProfiling;
  2360. },
  2361.  
  2362.  
  2363. createTemporaryProfile: function(title)
  2364. {
  2365. title = title || WebInspector.UIString("Recording\u2026");
  2366. return new WebInspector.CPUProfileHeader(this, title);
  2367. },
  2368.  
  2369.  
  2370. createProfile: function(profile)
  2371. {
  2372. return new WebInspector.CPUProfileHeader(this, profile.title, profile.uid);
  2373. },
  2374.  
  2375. __proto__: WebInspector.ProfileType.prototype
  2376. }
  2377.  
  2378.  
  2379. WebInspector.CPUProfileHeader = function(type, title, uid)
  2380. {
  2381. WebInspector.ProfileHeader.call(this, type, title, uid);
  2382. }
  2383.  
  2384. WebInspector.CPUProfileHeader.prototype = {
  2385.  
  2386. createSidebarTreeElement: function()
  2387. {
  2388. return new WebInspector.ProfileSidebarTreeElement(this, WebInspector.UIString("Profile %d"), "profile-sidebar-tree-item");
  2389. },
  2390.  
  2391.  
  2392. createView: function(profilesPanel)
  2393. {
  2394. return new WebInspector.CPUProfileView(this);
  2395. },
  2396.  
  2397. __proto__: WebInspector.ProfileHeader.prototype
  2398. }
  2399. ;
  2400.  
  2401.  
  2402.  
  2403. WebInspector.CSSSelectorDataGridNode = function(profileView, data)
  2404. {
  2405. WebInspector.DataGridNode.call(this, data, false);
  2406. this._profileView = profileView;
  2407. }
  2408.  
  2409. WebInspector.CSSSelectorDataGridNode.prototype = {
  2410. get data()
  2411. {
  2412. var data = {};
  2413. data.selector = this._data.selector;
  2414. data.matches = this._data.matchCount;
  2415.  
  2416. if (this._profileView.showTimeAsPercent.get())
  2417. data.time = Number(this._data.timePercent).toFixed(1) + "%";
  2418. else
  2419. data.time = Number.secondsToString(this._data.time / 1000, true);
  2420.  
  2421. return data;
  2422. },
  2423.  
  2424. get rawData()
  2425. {
  2426. return this._data;
  2427. },
  2428.  
  2429. createCell: function(columnIdentifier)
  2430. {
  2431. var cell = WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier);
  2432. if (columnIdentifier === "selector" && cell.firstChild) {
  2433. cell.firstChild.title = this.rawData.selector;
  2434. return cell;
  2435. }
  2436.  
  2437. if (columnIdentifier !== "source")
  2438. return cell;
  2439.  
  2440. cell.removeChildren();
  2441.  
  2442. if (this.rawData.url) {
  2443. var wrapperDiv = cell.createChild("div");
  2444. wrapperDiv.appendChild(WebInspector.linkifyResourceAsNode(this.rawData.url, this.rawData.lineNumber));
  2445. }
  2446.  
  2447. return cell;
  2448. },
  2449.  
  2450. __proto__: WebInspector.DataGridNode.prototype
  2451. }
  2452.  
  2453.  
  2454. WebInspector.CSSSelectorProfileView = function(profile)
  2455. {
  2456. WebInspector.View.call(this);
  2457.  
  2458. this.element.addStyleClass("profile-view");
  2459.  
  2460. this.showTimeAsPercent = WebInspector.settings.createSetting("selectorProfilerShowTimeAsPercent", true);
  2461.  
  2462. var columns = { "selector": { title: WebInspector.UIString("Selector"), width: "550px", sortable: true },
  2463. "source": { title: WebInspector.UIString("Source"), width: "100px", sortable: true },
  2464. "time": { title: WebInspector.UIString("Total"), width: "72px", sort: "descending", sortable: true },
  2465. "matches": { title: WebInspector.UIString("Matches"), width: "72px", sortable: true } };
  2466.  
  2467. this.dataGrid = new WebInspector.DataGrid(columns);
  2468. this.dataGrid.element.addStyleClass("selector-profile-view");
  2469. this.dataGrid.addEventListener("sorting changed", this._sortProfile, this);
  2470. this.dataGrid.element.addEventListener("mousedown", this._mouseDownInDataGrid.bind(this), true);
  2471. this.dataGrid.show(this.element);
  2472.  
  2473. this.percentButton = new WebInspector.StatusBarButton("", "percent-time-status-bar-item");
  2474. this.percentButton.addEventListener("click", this._percentClicked, this);
  2475.  
  2476. this.profile = profile;
  2477.  
  2478. this._createProfileNodes();
  2479. this._sortProfile();
  2480. this._updatePercentButton();
  2481. }
  2482.  
  2483. WebInspector.CSSSelectorProfileView.prototype = {
  2484. get statusBarItems()
  2485. {
  2486. return [this.percentButton.element];
  2487. },
  2488.  
  2489. get profile()
  2490. {
  2491. return this._profile;
  2492. },
  2493.  
  2494. set profile(profile)
  2495. {
  2496. this._profile = profile;
  2497. },
  2498.  
  2499. _createProfileNodes: function()
  2500. {
  2501. var data = this.profile.data;
  2502. if (!data) {
  2503.  
  2504. return;
  2505. }
  2506.  
  2507. this.profile.children = [];
  2508. for (var i = 0; i < data.length; ++i) {
  2509. data[i].timePercent = data[i].time * 100 / this.profile.totalTime;
  2510. var node = new WebInspector.CSSSelectorDataGridNode(this, data[i]);
  2511. this.profile.children.push(node);
  2512. }
  2513. },
  2514.  
  2515. rebuildGridItems: function()
  2516. {
  2517. this.dataGrid.rootNode().removeChildren();
  2518.  
  2519. var children = this.profile.children;
  2520. var count = children.length;
  2521.  
  2522. for (var index = 0; index < count; ++index)
  2523. this.dataGrid.rootNode().appendChild(children[index]);
  2524. },
  2525.  
  2526. refreshData: function()
  2527. {
  2528. var child = this.dataGrid.rootNode().children[0];
  2529. while (child) {
  2530. child.refresh();
  2531. child = child.traverseNextNode(false, null, true);
  2532. }
  2533. },
  2534.  
  2535. refreshShowAsPercents: function()
  2536. {
  2537. this._updatePercentButton();
  2538. this.refreshData();
  2539. },
  2540.  
  2541. _percentClicked: function(event)
  2542. {
  2543. this.showTimeAsPercent.set(!this.showTimeAsPercent.get());
  2544. this.refreshShowAsPercents();
  2545. },
  2546.  
  2547. _updatePercentButton: function()
  2548. {
  2549. if (this.showTimeAsPercent.get()) {
  2550. this.percentButton.title = WebInspector.UIString("Show absolute times.");
  2551. this.percentButton.toggled = true;
  2552. } else {
  2553. this.percentButton.title = WebInspector.UIString("Show times as percentages.");
  2554. this.percentButton.toggled = false;
  2555. }
  2556. },
  2557.  
  2558. _sortProfile: function()
  2559. {
  2560. var sortAscending = this.dataGrid.sortOrder === "ascending";
  2561. var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier;
  2562.  
  2563. function selectorComparator(a, b)
  2564. {
  2565. var result = b.rawData.selector.localeCompare(a.rawData.selector);
  2566. return sortAscending ? -result : result;
  2567. }
  2568.  
  2569. function sourceComparator(a, b)
  2570. {
  2571. var aRawData = a.rawData;
  2572. var bRawData = b.rawData;
  2573. var result = bRawData.url.localeCompare(aRawData.url);
  2574. if (!result)
  2575. result = bRawData.lineNumber - aRawData.lineNumber;
  2576. return sortAscending ? -result : result;
  2577. }
  2578.  
  2579. function timeComparator(a, b)
  2580. {
  2581. const result = b.rawData.time - a.rawData.time;
  2582. return sortAscending ? -result : result;
  2583. }
  2584.  
  2585. function matchesComparator(a, b)
  2586. {
  2587. const result = b.rawData.matchCount - a.rawData.matchCount;
  2588. return sortAscending ? -result : result;
  2589. }
  2590.  
  2591. var comparator;
  2592. switch (sortColumnIdentifier) {
  2593. case "time":
  2594. comparator = timeComparator;
  2595. break;
  2596. case "matches":
  2597. comparator = matchesComparator;
  2598. break;
  2599. case "selector":
  2600. comparator = selectorComparator;
  2601. break;
  2602. case "source":
  2603. comparator = sourceComparator;
  2604. break;
  2605. }
  2606.  
  2607. this.profile.children.sort(comparator);
  2608.  
  2609. this.rebuildGridItems();
  2610. },
  2611.  
  2612. _mouseDownInDataGrid: function(event)
  2613. {
  2614. if (event.detail < 2)
  2615. return;
  2616.  
  2617. var cell = event.target.enclosingNodeOrSelfWithNodeName("td");
  2618. if (!cell)
  2619. return;
  2620.  
  2621. if (cell.hasStyleClass("time-column"))
  2622. this.showTimeAsPercent.set(!this.showTimeAsPercent.get());
  2623. else
  2624. return;
  2625.  
  2626. this.refreshShowAsPercents();
  2627.  
  2628. event.consume(true);
  2629. },
  2630.  
  2631. __proto__: WebInspector.View.prototype
  2632. }
  2633.  
  2634.  
  2635. WebInspector.CSSSelectorProfileType = function()
  2636. {
  2637. WebInspector.ProfileType.call(this, WebInspector.CSSSelectorProfileType.TypeId, WebInspector.UIString("Collect CSS Selector Profile"));
  2638. this._recording = false;
  2639. this._profileUid = 1;
  2640. WebInspector.CSSSelectorProfileType.instance = this;
  2641. }
  2642.  
  2643. WebInspector.CSSSelectorProfileType.TypeId = "SELECTOR";
  2644.  
  2645. WebInspector.CSSSelectorProfileType.prototype = {
  2646. get buttonTooltip()
  2647. {
  2648. return this._recording ? WebInspector.UIString("Stop CSS selector profiling.") : WebInspector.UIString("Start CSS selector profiling.");
  2649. },
  2650.  
  2651.  
  2652. buttonClicked: function(profilesPanel)
  2653. {
  2654. if (this._recording) {
  2655. this._stopRecordingProfile(profilesPanel);
  2656. return false;
  2657. } else {
  2658. this._startRecordingProfile(profilesPanel);
  2659. return true;
  2660. }
  2661. },
  2662.  
  2663. get treeItemTitle()
  2664. {
  2665. return WebInspector.UIString("CSS SELECTOR PROFILES");
  2666. },
  2667.  
  2668. get description()
  2669. {
  2670. return WebInspector.UIString("CSS selector profiles show how long the selector matching has taken in total and how many times a certain selector has matched DOM elements (the results are approximate due to matching algorithm optimizations.)");
  2671. },
  2672.  
  2673. reset: function()
  2674. {
  2675. this._profileUid = 1;
  2676. },
  2677.  
  2678. setRecordingProfile: function(isProfiling)
  2679. {
  2680. this._recording = isProfiling;
  2681. },
  2682.  
  2683.  
  2684. _startRecordingProfile: function(profilesPanel)
  2685. {
  2686. this._recording = true;
  2687. CSSAgent.startSelectorProfiler();
  2688. profilesPanel.setRecordingProfile(WebInspector.CSSSelectorProfileType.TypeId, true);
  2689. },
  2690.  
  2691.  
  2692. _stopRecordingProfile: function(profilesPanel)
  2693. {
  2694.  
  2695. function callback(error, profile)
  2696. {
  2697. if (error)
  2698. return;
  2699.  
  2700. var uid = this._profileUid++;
  2701. var title = WebInspector.UIString("Profile %d", uid) + String.sprintf(" (%s)", Number.secondsToString(profile.totalTime / 1000));
  2702. var profileHeader = new WebInspector.CSSProfileHeader(this, title, uid, profile);
  2703. profilesPanel.addProfileHeader(profileHeader);
  2704. profilesPanel.setRecordingProfile(WebInspector.CSSSelectorProfileType.TypeId, false);
  2705. }
  2706.  
  2707. this._recording = false;
  2708. CSSAgent.stopSelectorProfiler(callback.bind(this));
  2709. },
  2710.  
  2711.  
  2712. createTemporaryProfile: function(title)
  2713. {
  2714. title = title || WebInspector.UIString("Recording\u2026");
  2715. return new WebInspector.CSSProfileHeader(this, title);
  2716. },
  2717.  
  2718. __proto__: WebInspector.ProfileType.prototype
  2719. }
  2720.  
  2721.  
  2722.  
  2723. WebInspector.CSSProfileHeader = function(type, title, uid, protocolData)
  2724. {
  2725. WebInspector.ProfileHeader.call(this, type, title, uid);
  2726. this._protocolData = protocolData;
  2727. }
  2728.  
  2729. WebInspector.CSSProfileHeader.prototype = {
  2730.  
  2731. createSidebarTreeElement: function()
  2732. {
  2733. return new WebInspector.ProfileSidebarTreeElement(this, this.title, "profile-sidebar-tree-item");
  2734. },
  2735.  
  2736.  
  2737. createView: function(profilesPanel)
  2738. {
  2739. var profile =   (this._protocolData);
  2740. return new WebInspector.CSSSelectorProfileView(profile);
  2741. },
  2742.  
  2743. __proto__: WebInspector.ProfileHeader.prototype
  2744. }
  2745. ;
  2746.  
  2747.  
  2748.  
  2749. WebInspector.HeapSnapshotArraySlice = function(array, start, end)
  2750. {
  2751. this._array = array;
  2752. this._start = start;
  2753. this.length = end - start;
  2754. }
  2755.  
  2756. WebInspector.HeapSnapshotArraySlice.prototype = {
  2757. item: function(index)
  2758. {
  2759. return this._array[this._start + index];
  2760. },
  2761.  
  2762. slice: function(start, end)
  2763. {
  2764. if (typeof end === "undefined")
  2765. end = this.length;
  2766. return this._array.subarray(this._start + start, this._start + end);
  2767. }
  2768. }
  2769.  
  2770.  
  2771. WebInspector.HeapSnapshotEdge = function(snapshot, edges, edgeIndex)
  2772. {
  2773. this._snapshot = snapshot;
  2774. this._edges = edges;
  2775. this.edgeIndex = edgeIndex || 0;
  2776. }
  2777.  
  2778. WebInspector.HeapSnapshotEdge.prototype = {
  2779. clone: function()
  2780. {
  2781. return new WebInspector.HeapSnapshotEdge(this._snapshot, this._edges, this.edgeIndex);
  2782. },
  2783.  
  2784. hasStringName: function()
  2785. {
  2786. if (!this.isShortcut())
  2787. return this._hasStringName();
  2788. return isNaN(parseInt(this._name(), 10));
  2789. },
  2790.  
  2791. isElement: function()
  2792. {
  2793. return this._type() === this._snapshot._edgeElementType;
  2794. },
  2795.  
  2796. isHidden: function()
  2797. {
  2798. return this._type() === this._snapshot._edgeHiddenType;
  2799. },
  2800.  
  2801. isWeak: function()
  2802. {
  2803. return this._type() === this._snapshot._edgeWeakType;
  2804. },
  2805.  
  2806. isInternal: function()
  2807. {
  2808. return this._type() === this._snapshot._edgeInternalType;
  2809. },
  2810.  
  2811. isInvisible: function()
  2812. {
  2813. return this._type() === this._snapshot._edgeInvisibleType;
  2814. },
  2815.  
  2816. isShortcut: function()
  2817. {
  2818. return this._type() === this._snapshot._edgeShortcutType;
  2819. },
  2820.  
  2821. name: function()
  2822. {
  2823. if (!this.isShortcut())
  2824. return this._name();
  2825. var numName = parseInt(this._name(), 10);
  2826. return isNaN(numName) ? this._name() : numName;
  2827. },
  2828.  
  2829. node: function()
  2830. {
  2831. return new WebInspector.HeapSnapshotNode(this._snapshot, this.nodeIndex());
  2832. },
  2833.  
  2834. nodeIndex: function()
  2835. {
  2836. return this._edges.item(this.edgeIndex + this._snapshot._edgeToNodeOffset);
  2837. },
  2838.  
  2839. rawEdges: function()
  2840. {
  2841. return this._edges;
  2842. },
  2843.  
  2844. toString: function()
  2845. {
  2846. var name = this.name();
  2847. switch (this.type()) {
  2848. case "context": return "->" + name;
  2849. case "element": return "[" + name + "]";
  2850. case "weak": return "[[" + name + "]]";
  2851. case "property":
  2852. return name.indexOf(" ") === -1 ? "." + name : "[\"" + name + "\"]";
  2853. case "shortcut":
  2854. if (typeof name === "string")
  2855. return name.indexOf(" ") === -1 ? "." + name : "[\"" + name + "\"]";
  2856. else
  2857. return "[" + name + "]";
  2858. case "internal":
  2859. case "hidden":
  2860. case "invisible":
  2861. return "{" + name + "}";
  2862. };
  2863. return "?" + name + "?";
  2864. },
  2865.  
  2866. type: function()
  2867. {
  2868. return this._snapshot._edgeTypes[this._type()];
  2869. },
  2870.  
  2871. _hasStringName: function()
  2872. {
  2873. return !this.isElement() && !this.isHidden() && !this.isWeak();
  2874. },
  2875.  
  2876. _name: function()
  2877. {
  2878. return this._hasStringName() ? this._snapshot._strings[this._nameOrIndex()] : this._nameOrIndex();
  2879. },
  2880.  
  2881. _nameOrIndex: function()
  2882. {
  2883. return this._edges.item(this.edgeIndex + this._snapshot._edgeNameOffset);
  2884. },
  2885.  
  2886. _type: function()
  2887. {
  2888. return this._edges.item(this.edgeIndex + this._snapshot._edgeTypeOffset);
  2889. }
  2890. };
  2891.  
  2892.  
  2893. WebInspector.HeapSnapshotEdgeIterator = function(edge)
  2894. {
  2895. this.edge = edge;
  2896. }
  2897.  
  2898. WebInspector.HeapSnapshotEdgeIterator.prototype = {
  2899. first: function()
  2900. {
  2901. this.edge.edgeIndex = 0;
  2902. },
  2903.  
  2904. hasNext: function()
  2905. {
  2906. return this.edge.edgeIndex < this.edge._edges.length;
  2907. },
  2908.  
  2909. index: function()
  2910. {
  2911. return this.edge.edgeIndex;
  2912. },
  2913.  
  2914. setIndex: function(newIndex)
  2915. {
  2916. this.edge.edgeIndex = newIndex;
  2917. },
  2918.  
  2919. item: function()
  2920. {
  2921. return this.edge;
  2922. },
  2923.  
  2924. next: function()
  2925. {
  2926. this.edge.edgeIndex += this.edge._snapshot._edgeFieldsCount;
  2927. }
  2928. };
  2929.  
  2930.  
  2931. WebInspector.HeapSnapshotRetainerEdge = function(snapshot, retainedNodeIndex, retainerIndex)
  2932. {
  2933. this._snapshot = snapshot;
  2934. this._retainedNodeIndex = retainedNodeIndex;
  2935.  
  2936. var retainedNodeOrdinal = retainedNodeIndex / snapshot._nodeFieldCount;
  2937. this._firstRetainer = snapshot._firstRetainerIndex[retainedNodeOrdinal];
  2938. this._retainersCount = snapshot._firstRetainerIndex[retainedNodeOrdinal + 1] - this._firstRetainer;
  2939.  
  2940. this.setRetainerIndex(retainerIndex);
  2941. }
  2942.  
  2943. WebInspector.HeapSnapshotRetainerEdge.prototype = {
  2944. clone: function()
  2945. {
  2946. return new WebInspector.HeapSnapshotRetainerEdge(this._snapshot, this._retainedNodeIndex, this.retainerIndex());
  2947. },
  2948.  
  2949. hasStringName: function()
  2950. {
  2951. return this._edge().hasStringName();
  2952. },
  2953.  
  2954. isElement: function()
  2955. {
  2956. return this._edge().isElement();
  2957. },
  2958.  
  2959. isHidden: function()
  2960. {
  2961. return this._edge().isHidden();
  2962. },
  2963.  
  2964. isInternal: function()
  2965. {
  2966. return this._edge().isInternal();
  2967. },
  2968.  
  2969. isInvisible: function()
  2970. {
  2971. return this._edge().isInvisible();
  2972. },
  2973.  
  2974. isShortcut: function()
  2975. {
  2976. return this._edge().isShortcut();
  2977. },
  2978.  
  2979. isWeak: function()
  2980. {
  2981. return this._edge().isWeak();
  2982. },
  2983.  
  2984. name: function()
  2985. {
  2986. return this._edge().name();
  2987. },
  2988.  
  2989. node: function()
  2990. {
  2991. return this._node();
  2992. },
  2993.  
  2994. nodeIndex: function()
  2995. {
  2996. return this._nodeIndex;
  2997. },
  2998.  
  2999. retainerIndex: function()
  3000. {
  3001. return this._retainerIndex;
  3002. },
  3003.  
  3004. setRetainerIndex: function(newIndex)
  3005. {
  3006. if (newIndex !== this._retainerIndex) {
  3007. this._retainerIndex = newIndex;
  3008. this.edgeIndex = newIndex;
  3009. }
  3010. },
  3011.  
  3012. set edgeIndex(edgeIndex)
  3013. {
  3014. var retainerIndex = this._firstRetainer + edgeIndex;
  3015. this._globalEdgeIndex = this._snapshot._retainingEdges[retainerIndex];
  3016. this._nodeIndex = this._snapshot._retainingNodes[retainerIndex];
  3017. delete this._edgeInstance;
  3018. delete this._nodeInstance;
  3019. },
  3020.  
  3021. _node: function()
  3022. {
  3023. if (!this._nodeInstance)
  3024. this._nodeInstance = new WebInspector.HeapSnapshotNode(this._snapshot, this._nodeIndex);
  3025. return this._nodeInstance;
  3026. },
  3027.  
  3028. _edge: function()
  3029. {
  3030. if (!this._edgeInstance) {
  3031. var edgeIndex = this._globalEdgeIndex - this._node()._edgeIndexesStart();
  3032. this._edgeInstance = new WebInspector.HeapSnapshotEdge(this._snapshot, this._node().rawEdges(), edgeIndex);
  3033. }
  3034. return this._edgeInstance;
  3035. },
  3036.  
  3037. toString: function()
  3038. {
  3039. return this._edge().toString();
  3040. },
  3041.  
  3042. type: function()
  3043. {
  3044. return this._edge().type();
  3045. }
  3046. }
  3047.  
  3048.  
  3049. WebInspector.HeapSnapshotRetainerEdgeIterator = function(retainer)
  3050. {
  3051. this.retainer = retainer;
  3052. }
  3053.  
  3054. WebInspector.HeapSnapshotRetainerEdgeIterator.prototype = {
  3055. first: function()
  3056. {
  3057. this.retainer.setRetainerIndex(0);
  3058. },
  3059.  
  3060. hasNext: function()
  3061. {
  3062. return this.retainer.retainerIndex() < this.retainer._retainersCount;
  3063. },
  3064.  
  3065. index: function()
  3066. {
  3067. return this.retainer.retainerIndex();
  3068. },
  3069.  
  3070. setIndex: function(newIndex)
  3071. {
  3072. this.retainer.setRetainerIndex(newIndex);
  3073. },
  3074.  
  3075. item: function()
  3076. {
  3077. return this.retainer;
  3078. },
  3079.  
  3080. next: function()
  3081. {
  3082. this.retainer.setRetainerIndex(this.retainer.retainerIndex() + 1);
  3083. }
  3084. };
  3085.  
  3086.  
  3087. WebInspector.HeapSnapshotNode = function(snapshot, nodeIndex)
  3088. {
  3089. this._snapshot = snapshot;
  3090. this._firstNodeIndex = nodeIndex;
  3091. this.nodeIndex = nodeIndex;
  3092. }
  3093.  
  3094. WebInspector.HeapSnapshotNode.prototype = {
  3095. canBeQueried: function()
  3096. {
  3097. var flags = this._snapshot._flagsOfNode(this);
  3098. return !!(flags & this._snapshot._nodeFlags.canBeQueried);
  3099. },
  3100.  
  3101. isPageObject: function()
  3102. {
  3103. var flags = this._snapshot._flagsOfNode(this);
  3104. return !!(flags & this._snapshot._nodeFlags.pageObject);
  3105. },
  3106.  
  3107. distanceToWindow: function()
  3108. {
  3109. return this._snapshot._distancesToWindow[this.nodeIndex / this._snapshot._nodeFieldCount];
  3110. },
  3111.  
  3112. className: function()
  3113. {
  3114. var type = this.type();
  3115. switch (type) {
  3116. case "hidden":
  3117. return WebInspector.UIString("(system)");
  3118. case "object":
  3119. case "native":
  3120. return this.name();
  3121. case "code":
  3122. return WebInspector.UIString("(compiled code)");
  3123. default:
  3124. return "(" + type + ")";
  3125. }
  3126. },
  3127.  
  3128. classIndex: function()
  3129. {
  3130. var snapshot = this._snapshot;
  3131. var nodes = snapshot._nodes;
  3132. var type = nodes[this.nodeIndex + snapshot._nodeTypeOffset];;
  3133. if (type === snapshot._nodeObjectType || type === snapshot._nodeNativeType)
  3134. return nodes[this.nodeIndex + snapshot._nodeNameOffset];
  3135. return -1 - type;
  3136. },
  3137.  
  3138. dominatorIndex: function()
  3139. {
  3140. var nodeFieldCount = this._snapshot._nodeFieldCount;
  3141. return this._snapshot._dominatorsTree[this.nodeIndex / this._snapshot._nodeFieldCount] * nodeFieldCount;
  3142. },
  3143.  
  3144. edges: function()
  3145. {
  3146. return new WebInspector.HeapSnapshotEdgeIterator(new WebInspector.HeapSnapshotEdge(this._snapshot, this.rawEdges()));
  3147. },
  3148.  
  3149. edgesCount: function()
  3150. {
  3151. return (this._edgeIndexesEnd() - this._edgeIndexesStart()) / this._snapshot._edgeFieldsCount;
  3152. },
  3153.  
  3154. flags: function()
  3155. {
  3156. return this._snapshot._flagsOfNode(this);
  3157. },
  3158.  
  3159. id: function()
  3160. {
  3161. var snapshot = this._snapshot;
  3162. return snapshot._nodes[this.nodeIndex + snapshot._nodeIdOffset];
  3163. },
  3164.  
  3165. isHidden: function()
  3166. {
  3167. return this._type() === this._snapshot._nodeHiddenType;
  3168. },
  3169.  
  3170. isNative: function()
  3171. {
  3172. return this._type() === this._snapshot._nodeNativeType;
  3173. },
  3174.  
  3175. isSynthetic: function()
  3176. {
  3177. return this._type() === this._snapshot._nodeSyntheticType;
  3178. },
  3179.  
  3180. isWindow: function()
  3181. {
  3182. const windowRE = /^Window/;
  3183. return windowRE.test(this.name());
  3184. },
  3185.  
  3186. isDetachedDOMTreesRoot: function()
  3187. {
  3188. return this.name() === "(Detached DOM trees)";
  3189. },
  3190.  
  3191. isDetachedDOMTree: function()
  3192. {
  3193. const detachedDOMTreeRE = /^Detached DOM tree/;
  3194. return detachedDOMTreeRE.test(this.className());
  3195. },
  3196.  
  3197. isRoot: function()
  3198. {
  3199. return this.nodeIndex === this._snapshot._rootNodeIndex;
  3200. },
  3201.  
  3202. name: function()
  3203. {
  3204. return this._snapshot._strings[this._name()];
  3205. },
  3206.  
  3207. rawEdges: function()
  3208. {
  3209. return new WebInspector.HeapSnapshotArraySlice(this._snapshot._containmentEdges, this._edgeIndexesStart(), this._edgeIndexesEnd());
  3210. },
  3211.  
  3212. retainedSize: function()
  3213. {
  3214. var snapshot = this._snapshot;
  3215. return snapshot._nodes[this.nodeIndex + snapshot._nodeRetainedSizeOffset];
  3216. },
  3217.  
  3218. retainers: function()
  3219. {
  3220. return new WebInspector.HeapSnapshotRetainerEdgeIterator(new WebInspector.HeapSnapshotRetainerEdge(this._snapshot, this.nodeIndex, 0));
  3221. },
  3222.  
  3223. selfSize: function()
  3224. {
  3225. var snapshot = this._snapshot;
  3226. return snapshot._nodes[this.nodeIndex + snapshot._nodeSelfSizeOffset];
  3227. },
  3228.  
  3229. type: function()
  3230. {
  3231. return this._snapshot._nodeTypes[this._type()];
  3232. },
  3233.  
  3234. _name: function()
  3235. {
  3236. var snapshot = this._snapshot;
  3237. return snapshot._nodes[this.nodeIndex + snapshot._nodeNameOffset];
  3238. },
  3239.  
  3240. _edgeIndexesStart: function()
  3241. {
  3242. return this._snapshot._firstEdgeIndexes[this._ordinal()];
  3243. },
  3244.  
  3245. _edgeIndexesEnd: function()
  3246. {
  3247. return this._snapshot._firstEdgeIndexes[this._ordinal() + 1];
  3248. },
  3249.  
  3250. _ordinal: function()
  3251. {
  3252. return this.nodeIndex / this._snapshot._nodeFieldCount;
  3253. },
  3254.  
  3255. _nextNodeIndex: function()
  3256. {
  3257. return this.nodeIndex + this._snapshot._nodeFieldCount;
  3258. },
  3259.  
  3260. _type: function()
  3261. {
  3262. var snapshot = this._snapshot;
  3263. return snapshot._nodes[this.nodeIndex + snapshot._nodeTypeOffset];
  3264. }
  3265. };
  3266.  
  3267.  
  3268. WebInspector.HeapSnapshotNodeIterator = function(node)
  3269. {
  3270. this.node = node;
  3271. this._nodesLength = node._snapshot._nodes.length;
  3272. }
  3273.  
  3274. WebInspector.HeapSnapshotNodeIterator.prototype = {
  3275. first: function()
  3276. {
  3277. this.node.nodeIndex = this.node._firstNodeIndex;
  3278. },
  3279.  
  3280. hasNext: function()
  3281. {
  3282. return this.node.nodeIndex < this._nodesLength;
  3283. },
  3284.  
  3285. index: function()
  3286. {
  3287. return this.node.nodeIndex;
  3288. },
  3289.  
  3290. setIndex: function(newIndex)
  3291. {
  3292. this.node.nodeIndex = newIndex;
  3293. },
  3294.  
  3295. item: function()
  3296. {
  3297. return this.node;
  3298. },
  3299.  
  3300. next: function()
  3301. {
  3302. this.node.nodeIndex = this.node._nextNodeIndex();
  3303. }
  3304. }
  3305.  
  3306.  
  3307. WebInspector.HeapSnapshot = function(profile)
  3308. {
  3309. this.uid = profile.snapshot.uid;
  3310. this._nodes = profile.nodes;
  3311. this._containmentEdges = profile.edges;
  3312.  
  3313. this._metaNode = profile.snapshot.meta;
  3314. this._strings = profile.strings;
  3315.  
  3316. this._snapshotDiffs = {};
  3317. this._aggregatesForDiff = null;
  3318.  
  3319. this._init();
  3320. }
  3321.  
  3322.  
  3323. function HeapSnapshotMetainfo()
  3324. {
  3325.  
  3326. this.node_fields = [];
  3327. this.node_types = [];
  3328. this.edge_fields = [];
  3329. this.edge_types = [];
  3330.  
  3331.  
  3332. this.fields = [];
  3333. this.types = [];
  3334. }
  3335.  
  3336.  
  3337. function HeapSnapshotHeader()
  3338. {
  3339.  
  3340. this.title = "";
  3341. this.uid = 0;
  3342. this.meta = new HeapSnapshotMetainfo();
  3343. this.node_count = 0;
  3344. this.edge_count = 0;
  3345. }
  3346.  
  3347. WebInspector.HeapSnapshot.prototype = {
  3348. _init: function()
  3349. {
  3350. var meta = this._metaNode;
  3351. this._rootNodeIndex = 0;
  3352.  
  3353. this._nodeTypeOffset = meta.node_fields.indexOf("type");
  3354. this._nodeNameOffset = meta.node_fields.indexOf("name");
  3355. this._nodeIdOffset = meta.node_fields.indexOf("id");
  3356. this._nodeSelfSizeOffset = meta.node_fields.indexOf("self_size");
  3357. this._nodeEdgeCountOffset = meta.node_fields.indexOf("edge_count");
  3358. this._nodeFieldCount = meta.node_fields.length;
  3359.  
  3360. this._nodeTypes = meta.node_types[this._nodeTypeOffset];
  3361. this._nodeHiddenType = this._nodeTypes.indexOf("hidden");
  3362. this._nodeObjectType = this._nodeTypes.indexOf("object");
  3363. this._nodeNativeType = this._nodeTypes.indexOf("native");
  3364. this._nodeCodeType = this._nodeTypes.indexOf("code");
  3365. this._nodeSyntheticType = this._nodeTypes.indexOf("synthetic");
  3366.  
  3367. this._edgeFieldsCount = meta.edge_fields.length;
  3368. this._edgeTypeOffset = meta.edge_fields.indexOf("type");
  3369. this._edgeNameOffset = meta.edge_fields.indexOf("name_or_index");
  3370. this._edgeToNodeOffset = meta.edge_fields.indexOf("to_node");
  3371.  
  3372. this._edgeTypes = meta.edge_types[this._edgeTypeOffset];
  3373. this._edgeTypes.push("invisible");
  3374. this._edgeElementType = this._edgeTypes.indexOf("element");
  3375. this._edgeHiddenType = this._edgeTypes.indexOf("hidden");
  3376. this._edgeInternalType = this._edgeTypes.indexOf("internal");
  3377. this._edgeShortcutType = this._edgeTypes.indexOf("shortcut");
  3378. this._edgeWeakType = this._edgeTypes.indexOf("weak");
  3379. this._edgeInvisibleType = this._edgeTypes.indexOf("invisible");
  3380.  
  3381. this._nodeFlags = { 
  3382. canBeQueried: 1,
  3383. detachedDOMTreeNode: 2,
  3384. pageObject: 4, 
  3385.  
  3386. visitedMarkerMask: 0x0ffff, 
  3387. visitedMarker:     0x10000  
  3388. };
  3389.  
  3390. this.nodeCount = this._nodes.length / this._nodeFieldCount;
  3391. this._edgeCount = this._containmentEdges.length / this._edgeFieldsCount;
  3392.  
  3393. this._buildEdgeIndexes();
  3394. this._markInvisibleEdges();
  3395. this._buildRetainers();
  3396. this._calculateFlags();
  3397. this._calculateObjectToWindowDistance();
  3398. var result = this._buildPostOrderIndex();
  3399.  
  3400. this._dominatorsTree = this._buildDominatorTree(result.postOrderIndex2NodeOrdinal, result.nodeOrdinal2PostOrderIndex);
  3401. this._calculateRetainedSizes(result.postOrderIndex2NodeOrdinal);
  3402. this._buildDominatedNodes();
  3403. },
  3404.  
  3405. _buildEdgeIndexes: function()
  3406. {
  3407.  
  3408. if (this._nodeEdgeCountOffset === -1) {
  3409. var nodes = this._nodes;
  3410. var nodeCount = this.nodeCount;
  3411. var firstEdgeIndexes = this._firstEdgeIndexes = new Uint32Array(nodeCount + 1);
  3412. var nodeFieldCount = this._nodeFieldCount;
  3413. var nodeEdgesIndexOffset = this._metaNode.node_fields.indexOf("edges_index");
  3414. firstEdgeIndexes[nodeCount] = this._containmentEdges.length;
  3415. for (var nodeOrdinal = 0; nodeOrdinal < nodeCount; ++nodeOrdinal) {
  3416. firstEdgeIndexes[nodeOrdinal] = nodes[nodeOrdinal * nodeFieldCount + nodeEdgesIndexOffset];
  3417. }
  3418. return;
  3419. }
  3420.  
  3421. var nodes = this._nodes;
  3422. var nodeCount = this.nodeCount;
  3423. var firstEdgeIndexes = this._firstEdgeIndexes = new Uint32Array(nodeCount + 1);
  3424. var nodeFieldCount = this._nodeFieldCount;
  3425. var edgeFieldsCount = this._edgeFieldsCount;
  3426. var nodeEdgeCountOffset = this._nodeEdgeCountOffset;
  3427. firstEdgeIndexes[nodeCount] = this._containmentEdges.length;
  3428. for (var nodeOrdinal = 0, edgeIndex = 0; nodeOrdinal < nodeCount; ++nodeOrdinal) {
  3429. firstEdgeIndexes[nodeOrdinal] = edgeIndex;
  3430. edgeIndex += nodes[nodeOrdinal * nodeFieldCount + nodeEdgeCountOffset] * edgeFieldsCount;
  3431. }
  3432. },
  3433.  
  3434. _buildRetainers: function()
  3435. {
  3436. var retainingNodes = this._retainingNodes = new Uint32Array(this._edgeCount);
  3437. var retainingEdges = this._retainingEdges = new Uint32Array(this._edgeCount);
  3438.  
  3439.  
  3440. var firstRetainerIndex = this._firstRetainerIndex = new Uint32Array(this.nodeCount + 1);
  3441.  
  3442. var containmentEdges = this._containmentEdges;
  3443. var edgeFieldsCount = this._edgeFieldsCount;
  3444. var nodeFieldCount = this._nodeFieldCount;
  3445. var edgeToNodeOffset = this._edgeToNodeOffset;
  3446. var nodes = this._nodes;
  3447. var firstEdgeIndexes = this._firstEdgeIndexes;
  3448. var nodeCount = this.nodeCount;
  3449.  
  3450. for (var toNodeFieldIndex = edgeToNodeOffset, l = containmentEdges.length; toNodeFieldIndex < l; toNodeFieldIndex += edgeFieldsCount) {
  3451. var toNodeIndex = containmentEdges[toNodeFieldIndex];
  3452. if (toNodeIndex % nodeFieldCount)
  3453. throw new Error("Invalid toNodeIndex " + toNodeIndex);
  3454. ++firstRetainerIndex[toNodeIndex / nodeFieldCount];
  3455. }
  3456. for (var i = 0, firstUnusedRetainerSlot = 0; i < nodeCount; i++) {
  3457. var retainersCount = firstRetainerIndex[i];
  3458. firstRetainerIndex[i] = firstUnusedRetainerSlot;
  3459. retainingNodes[firstUnusedRetainerSlot] = retainersCount;
  3460. firstUnusedRetainerSlot += retainersCount;
  3461. }
  3462. firstRetainerIndex[nodeCount] = retainingNodes.length;
  3463.  
  3464. var nextNodeFirstEdgeIndex = firstEdgeIndexes[0];
  3465. for (var srcNodeOrdinal = 0; srcNodeOrdinal < nodeCount; ++srcNodeOrdinal) {
  3466. var firstEdgeIndex = nextNodeFirstEdgeIndex;
  3467. nextNodeFirstEdgeIndex = firstEdgeIndexes[srcNodeOrdinal + 1];
  3468. var srcNodeIndex = srcNodeOrdinal * nodeFieldCount;
  3469. for (var edgeIndex = firstEdgeIndex; edgeIndex < nextNodeFirstEdgeIndex; edgeIndex += edgeFieldsCount) {
  3470. var toNodeIndex = containmentEdges[edgeIndex + edgeToNodeOffset];
  3471. if (toNodeIndex % nodeFieldCount)
  3472. throw new Error("Invalid toNodeIndex " + toNodeIndex);
  3473. var firstRetainerSlotIndex = firstRetainerIndex[toNodeIndex / nodeFieldCount];
  3474. var nextUnusedRetainerSlotIndex = firstRetainerSlotIndex + (--retainingNodes[firstRetainerSlotIndex]);
  3475. retainingNodes[nextUnusedRetainerSlotIndex] = srcNodeIndex;
  3476. retainingEdges[nextUnusedRetainerSlotIndex] = edgeIndex;
  3477. }
  3478. }
  3479. },
  3480.  
  3481. dispose: function()
  3482. {
  3483. delete this._nodes;
  3484. delete this._strings;
  3485. delete this._retainingEdges;
  3486. delete this._retainingNodes;
  3487. delete this._firstRetainerIndex;
  3488. if (this._aggregates) {
  3489. delete this._aggregates;
  3490. delete this._aggregatesSortedFlags;
  3491. }
  3492. delete this._dominatedNodes;
  3493. delete this._firstDominatedNodeIndex;
  3494. delete this._flags;
  3495. delete this._distancesToWindow;
  3496. delete this._dominatorsTree;
  3497. },
  3498.  
  3499. _allNodes: function()
  3500. {
  3501. return new WebInspector.HeapSnapshotNodeIterator(this.rootNode());
  3502. },
  3503.  
  3504. rootNode: function()
  3505. {
  3506. return new WebInspector.HeapSnapshotNode(this, this._rootNodeIndex);
  3507. },
  3508.  
  3509. get rootNodeIndex()
  3510. {
  3511. return this._rootNodeIndex;
  3512. },
  3513.  
  3514. get totalSize()
  3515. {
  3516. return this.rootNode().retainedSize();
  3517. },
  3518.  
  3519. _getDominatedIndex: function(nodeIndex)
  3520. {
  3521. if (nodeIndex % this._nodeFieldCount)
  3522. throw new Error("Invalid nodeIndex: " + nodeIndex);
  3523. return this._firstDominatedNodeIndex[nodeIndex / this._nodeFieldCount];
  3524. },
  3525.  
  3526. _dominatedNodesOfNode: function(node)
  3527. {
  3528. var dominatedIndexFrom = this._getDominatedIndex(node.nodeIndex);
  3529. var dominatedIndexTo = this._getDominatedIndex(node._nextNodeIndex());
  3530. return new WebInspector.HeapSnapshotArraySlice(this._dominatedNodes, dominatedIndexFrom, dominatedIndexTo);
  3531. },
  3532.  
  3533. _flagsOfNode: function(node)
  3534. {
  3535. return this._flags[node.nodeIndex / this._nodeFieldCount];
  3536. },
  3537.  
  3538.  
  3539. aggregates: function(sortedIndexes, key, filterString)
  3540. {
  3541. if (!this._aggregates) {
  3542. this._aggregates = {};
  3543. this._aggregatesSortedFlags = {};
  3544. }
  3545.  
  3546. var aggregatesByClassName = this._aggregates[key];
  3547. if (aggregatesByClassName) {
  3548. if (sortedIndexes && !this._aggregatesSortedFlags[key]) {
  3549. this._sortAggregateIndexes(aggregatesByClassName);
  3550. this._aggregatesSortedFlags[key] = sortedIndexes;
  3551. }
  3552. return aggregatesByClassName;
  3553. }
  3554.  
  3555. var filter;
  3556. if (filterString)
  3557. filter = this._parseFilter(filterString);
  3558.  
  3559. var aggregates = this._buildAggregates(filter);
  3560. this._calculateClassesRetainedSize(aggregates.aggregatesByClassIndex, filter);
  3561. aggregatesByClassName = aggregates.aggregatesByClassName;
  3562.  
  3563. if (sortedIndexes)
  3564. this._sortAggregateIndexes(aggregatesByClassName);
  3565.  
  3566. this._aggregatesSortedFlags[key] = sortedIndexes;
  3567. this._aggregates[key] = aggregatesByClassName;
  3568.  
  3569. return aggregatesByClassName;
  3570. },
  3571.  
  3572. aggregatesForDiff: function()
  3573. {
  3574. if (this._aggregatesForDiff)
  3575. return this._aggregatesForDiff;
  3576.  
  3577. var aggregatesByClassName = this.aggregates(true, "allObjects");
  3578. this._aggregatesForDiff  = {};
  3579.  
  3580. var node = new WebInspector.HeapSnapshotNode(this);
  3581. for (var className in aggregatesByClassName) {
  3582. var aggregate = aggregatesByClassName[className];
  3583. var indexes = aggregate.idxs;
  3584. var ids = new Array(indexes.length);
  3585. var selfSizes = new Array(indexes.length);
  3586. for (var i = 0; i < indexes.length; i++) {
  3587. node.nodeIndex = indexes[i];
  3588. ids[i] = node.id();
  3589. selfSizes[i] = node.selfSize();
  3590. }
  3591.  
  3592. this._aggregatesForDiff[className] = {
  3593. indexes: indexes,
  3594. ids: ids,
  3595. selfSizes: selfSizes
  3596. };
  3597. }
  3598. return this._aggregatesForDiff;
  3599. },
  3600.  
  3601. _calculateObjectToWindowDistance: function()
  3602. {
  3603. var nodeFieldCount = this._nodeFieldCount;
  3604. var distances = new Uint32Array(this.nodeCount);
  3605.  
  3606.  
  3607. var nodesToVisit = new Uint32Array(this.nodeCount);
  3608. var nodesToVisitLength = 0;
  3609. for (var iter = this.rootNode().edges(); iter.hasNext(); iter.next()) {
  3610. var node = iter.edge.node();
  3611. if (node.isWindow()) {
  3612. nodesToVisit[nodesToVisitLength++] = node.nodeIndex;
  3613. distances[node.nodeIndex / nodeFieldCount] = 1;
  3614. }
  3615. }
  3616. this._bfs(nodesToVisit, nodesToVisitLength, distances);
  3617.  
  3618.  
  3619. nodesToVisitLength = 0;
  3620. nodesToVisit[nodesToVisitLength++] = this._rootNodeIndex;
  3621. distances[this._rootNodeIndex / nodeFieldCount] = 1;
  3622. this._bfs(nodesToVisit, nodesToVisitLength, distances);
  3623. this._distancesToWindow = distances;
  3624. },
  3625.  
  3626. _bfs: function(nodesToVisit, nodesToVisitLength, distances)
  3627. {
  3628.  
  3629. var edgeFieldsCount = this._edgeFieldsCount;
  3630. var nodeFieldCount = this._nodeFieldCount;
  3631. var containmentEdges = this._containmentEdges;
  3632. var firstEdgeIndexes = this._firstEdgeIndexes;
  3633. var edgeToNodeOffset = this._edgeToNodeOffset;
  3634. var edgeTypeOffset = this._edgeTypeOffset;
  3635. var nodes = this._nodes;
  3636. var nodeCount = this.nodeCount;
  3637. var containmentEdgesLength = containmentEdges.length;
  3638. var edgeWeakType = this._edgeWeakType;
  3639. var edgeShortcutType = this._edgeShortcutType;
  3640.  
  3641. var index = 0;
  3642. while (index < nodesToVisitLength) {
  3643. var nodeIndex = nodesToVisit[index++]; 
  3644. var nodeOrdinal = nodeIndex / nodeFieldCount;
  3645. var distance = distances[nodeOrdinal] + 1;
  3646. var firstEdgeIndex = firstEdgeIndexes[nodeOrdinal];
  3647. var edgesEnd = firstEdgeIndexes[nodeOrdinal + 1];
  3648. for (var edgeIndex = firstEdgeIndex; edgeIndex < edgesEnd; edgeIndex += edgeFieldsCount) {
  3649. var edgeType = containmentEdges[edgeIndex + edgeTypeOffset];
  3650. if (edgeType == edgeWeakType)
  3651. continue;
  3652. var childNodeIndex = containmentEdges[edgeIndex + edgeToNodeOffset];
  3653. var childNodeOrdinal = childNodeIndex / nodeFieldCount;
  3654. if (distances[childNodeOrdinal])
  3655. continue;
  3656. distances[childNodeOrdinal] = distance;
  3657. nodesToVisit[nodesToVisitLength++] = childNodeIndex;
  3658. }
  3659. }
  3660. if (nodesToVisitLength > nodeCount)
  3661. throw new Error("BFS failed. Nodes to visit (" + nodesToVisitLength + ") is more than nodes count (" + nodeCount + ")");
  3662. },
  3663.  
  3664. _buildAggregates: function(filter)
  3665. {
  3666. var aggregates = {};
  3667. var aggregatesByClassName = {};
  3668. var classIndexes = [];
  3669. var nodes = this._nodes;
  3670. var flags = this._flags;
  3671. var nodesLength = nodes.length;
  3672. var nodeNativeType = this._nodeNativeType;
  3673. var nodeFieldCount = this._nodeFieldCount;
  3674. var selfSizeOffset = this._nodeSelfSizeOffset;
  3675. var nodeTypeOffset = this._nodeTypeOffset;
  3676. var pageObjectFlag = this._nodeFlags.pageObject;
  3677. var node = new WebInspector.HeapSnapshotNode(this, this._rootNodeIndex);
  3678. var distancesToWindow = this._distancesToWindow;
  3679.  
  3680. for (var nodeIndex = this._rootNodeIndex; nodeIndex < nodesLength; nodeIndex += nodeFieldCount) {
  3681. var nodeOrdinal = nodeIndex / nodeFieldCount;
  3682. if (!(flags[nodeOrdinal] & pageObjectFlag))
  3683. continue;
  3684. node.nodeIndex = nodeIndex;
  3685. if (filter && !filter(node))
  3686. continue;
  3687. var selfSize = nodes[nodeIndex + selfSizeOffset];
  3688. if (!selfSize && nodes[nodeIndex + nodeTypeOffset] !== nodeNativeType)
  3689. continue;
  3690. var classIndex = node.classIndex();
  3691. if (!(classIndex in aggregates)) {
  3692. var nodeType = node.type();
  3693. var nameMatters = nodeType === "object" || nodeType === "native";
  3694. var value = {
  3695. count: 1,
  3696. distanceToWindow: distancesToWindow[nodeOrdinal],
  3697. self: selfSize,
  3698. maxRet: 0,
  3699. type: nodeType,
  3700. name: nameMatters ? node.name() : null,
  3701. idxs: [nodeIndex]
  3702. };
  3703. aggregates[classIndex] = value;
  3704. classIndexes.push(classIndex);
  3705. aggregatesByClassName[node.className()] = value;
  3706. } else {
  3707. var clss = aggregates[classIndex];
  3708. clss.distanceToWindow = Math.min(clss.distanceToWindow, distancesToWindow[nodeOrdinal]);
  3709. ++clss.count;
  3710. clss.self += selfSize;
  3711. clss.idxs.push(nodeIndex);
  3712. }
  3713. }
  3714.  
  3715.  
  3716. for (var i = 0, l = classIndexes.length; i < l; ++i) {
  3717. var classIndex = classIndexes[i];
  3718. aggregates[classIndex].idxs = aggregates[classIndex].idxs.slice();
  3719. }
  3720. return {aggregatesByClassName: aggregatesByClassName, aggregatesByClassIndex: aggregates};
  3721. },
  3722.  
  3723. _calculateClassesRetainedSize: function(aggregates, filter)
  3724. {
  3725. var rootNodeIndex = this._rootNodeIndex;
  3726. var node = new WebInspector.HeapSnapshotNode(this, rootNodeIndex);
  3727. var list = [rootNodeIndex];
  3728. var sizes = [-1];
  3729. var classes = [];
  3730. var seenClassNameIndexes = {};
  3731. var nodeFieldCount = this._nodeFieldCount;
  3732. var nodeTypeOffset = this._nodeTypeOffset;
  3733. var nodeNativeType = this._nodeNativeType;
  3734. var dominatedNodes = this._dominatedNodes;
  3735. var nodes = this._nodes;
  3736. var flags = this._flags;
  3737. var pageObjectFlag = this._nodeFlags.pageObject;
  3738. var firstDominatedNodeIndex = this._firstDominatedNodeIndex;
  3739.  
  3740. while (list.length) {
  3741. var nodeIndex = list.pop();
  3742. node.nodeIndex = nodeIndex;
  3743. var classIndex = node.classIndex();
  3744. var seen = !!seenClassNameIndexes[classIndex];
  3745. var nodeOrdinal = nodeIndex / nodeFieldCount;
  3746. var dominatedIndexFrom = firstDominatedNodeIndex[nodeOrdinal];
  3747. var dominatedIndexTo = firstDominatedNodeIndex[nodeOrdinal + 1];
  3748.  
  3749. if (!seen &&
  3750. (flags[nodeOrdinal] & pageObjectFlag) &&
  3751. (!filter || filter(node)) &&
  3752. (node.selfSize() || nodes[nodeIndex + nodeTypeOffset] === nodeNativeType)
  3753. ) {
  3754. aggregates[classIndex].maxRet += node.retainedSize();
  3755. if (dominatedIndexFrom !== dominatedIndexTo) {
  3756. seenClassNameIndexes[classIndex] = true;
  3757. sizes.push(list.length);
  3758. classes.push(classIndex);
  3759. }
  3760. }
  3761. for (var i = dominatedIndexFrom; i < dominatedIndexTo; i++)
  3762. list.push(dominatedNodes[i]);
  3763.  
  3764. var l = list.length;
  3765. while (sizes[sizes.length - 1] === l) {
  3766. sizes.pop();
  3767. classIndex = classes.pop();
  3768. seenClassNameIndexes[classIndex] = false;
  3769. }
  3770. }
  3771. },
  3772.  
  3773. _sortAggregateIndexes: function(aggregates)
  3774. {
  3775. var nodeA = new WebInspector.HeapSnapshotNode(this);
  3776. var nodeB = new WebInspector.HeapSnapshotNode(this);
  3777. for (var clss in aggregates)
  3778. aggregates[clss].idxs.sort(
  3779. function(idxA, idxB) {
  3780. nodeA.nodeIndex = idxA;
  3781. nodeB.nodeIndex = idxB;
  3782. return nodeA.id() < nodeB.id() ? -1 : 1;
  3783. });
  3784. },
  3785.  
  3786. _buildPostOrderIndex: function()
  3787. {
  3788. var nodeFieldCount = this._nodeFieldCount;
  3789. var nodes = this._nodes;
  3790. var nodeCount = this.nodeCount;
  3791. var rootNodeOrdinal = this._rootNodeIndex / nodeFieldCount;
  3792.  
  3793. var edgeFieldsCount = this._edgeFieldsCount;
  3794. var edgeTypeOffset = this._edgeTypeOffset;
  3795. var edgeToNodeOffset = this._edgeToNodeOffset;
  3796. var edgeShortcutType = this._edgeShortcutType;
  3797. var firstEdgeIndexes = this._firstEdgeIndexes;
  3798. var containmentEdges = this._containmentEdges;
  3799. var containmentEdgesLength = this._containmentEdges.length;
  3800.  
  3801. var flags = this._flags;
  3802. var flag = this._nodeFlags.pageObject;
  3803.  
  3804. var nodesToVisit = new Uint32Array(nodeCount);
  3805. var postOrderIndex2NodeOrdinal = new Uint32Array(nodeCount);
  3806. var nodeOrdinal2PostOrderIndex = new Uint32Array(nodeCount);
  3807. var painted = new Uint8Array(nodeCount);
  3808. var nodesToVisitLength = 0;
  3809. var postOrderIndex = 0;
  3810. var grey = 1;
  3811. var black = 2;
  3812.  
  3813. nodesToVisit[nodesToVisitLength++] = rootNodeOrdinal;
  3814. painted[rootNodeOrdinal] = grey;
  3815.  
  3816. while (nodesToVisitLength) {
  3817. var nodeOrdinal = nodesToVisit[nodesToVisitLength - 1];
  3818. if (painted[nodeOrdinal] === grey) {
  3819. painted[nodeOrdinal] = black;
  3820. var nodeFlag = flags[nodeOrdinal] & flag;
  3821. var beginEdgeIndex = firstEdgeIndexes[nodeOrdinal];
  3822. var endEdgeIndex = firstEdgeIndexes[nodeOrdinal + 1];
  3823. for (var edgeIndex = beginEdgeIndex; edgeIndex < endEdgeIndex; edgeIndex += edgeFieldsCount) {
  3824. if (nodeOrdinal !== rootNodeOrdinal && containmentEdges[edgeIndex + edgeTypeOffset] === edgeShortcutType)
  3825. continue;
  3826. var childNodeIndex = containmentEdges[edgeIndex + edgeToNodeOffset];
  3827. var childNodeOrdinal = childNodeIndex / nodeFieldCount;
  3828. var childNodeFlag = flags[childNodeOrdinal] & flag;
  3829.  
  3830.  
  3831. if (nodeOrdinal !== rootNodeOrdinal && childNodeFlag && !nodeFlag)
  3832. continue;
  3833. if (!painted[childNodeOrdinal]) {
  3834. painted[childNodeOrdinal] = grey;
  3835. nodesToVisit[nodesToVisitLength++] = childNodeOrdinal;
  3836. }
  3837. }
  3838. } else {
  3839. nodeOrdinal2PostOrderIndex[nodeOrdinal] = postOrderIndex;
  3840. postOrderIndex2NodeOrdinal[postOrderIndex++] = nodeOrdinal;
  3841. --nodesToVisitLength;
  3842. }
  3843. }
  3844.  
  3845. if (postOrderIndex !== nodeCount)
  3846. throw new Error("Postordering failed. " + (nodeCount - postOrderIndex) + " hanging nodes");
  3847.  
  3848. return {postOrderIndex2NodeOrdinal: postOrderIndex2NodeOrdinal, nodeOrdinal2PostOrderIndex: nodeOrdinal2PostOrderIndex};
  3849. },
  3850.  
  3851.  
  3852.  
  3853.  
  3854.  
  3855. _buildDominatorTree: function(postOrderIndex2NodeOrdinal, nodeOrdinal2PostOrderIndex)
  3856. {
  3857. var nodeFieldCount = this._nodeFieldCount;
  3858. var nodes = this._nodes;
  3859. var firstRetainerIndex = this._firstRetainerIndex;
  3860. var retainingNodes = this._retainingNodes;
  3861. var retainingEdges = this._retainingEdges;
  3862. var edgeFieldsCount = this._edgeFieldsCount;
  3863. var edgeTypeOffset = this._edgeTypeOffset;
  3864. var edgeToNodeOffset = this._edgeToNodeOffset;
  3865. var edgeShortcutType = this._edgeShortcutType;
  3866. var firstEdgeIndexes = this._firstEdgeIndexes;
  3867. var containmentEdges = this._containmentEdges;
  3868. var containmentEdgesLength = this._containmentEdges.length;
  3869. var rootNodeIndex = this._rootNodeIndex;
  3870.  
  3871. var flags = this._flags;
  3872. var flag = this._nodeFlags.pageObject;
  3873.  
  3874. var nodesCount = postOrderIndex2NodeOrdinal.length;
  3875. var rootPostOrderedIndex = nodesCount - 1;
  3876. var noEntry = nodesCount;
  3877. var dominators = new Uint32Array(nodesCount);
  3878. for (var i = 0; i < rootPostOrderedIndex; ++i)
  3879. dominators[i] = noEntry;
  3880. dominators[rootPostOrderedIndex] = rootPostOrderedIndex;
  3881.  
  3882.  
  3883.  
  3884. var affected = new Uint8Array(nodesCount);
  3885. var nodeOrdinal;
  3886.  
  3887. nodeOrdinal = this._rootNodeIndex / nodeFieldCount;
  3888. var beginEdgeToNodeFieldIndex = firstEdgeIndexes[nodeOrdinal] + edgeToNodeOffset;
  3889. var endEdgeToNodeFieldIndex = firstEdgeIndexes[nodeOrdinal + 1];
  3890. for (var toNodeFieldIndex = beginEdgeToNodeFieldIndex;
  3891. toNodeFieldIndex < endEdgeToNodeFieldIndex;
  3892. toNodeFieldIndex += edgeFieldsCount) {
  3893. var childNodeOrdinal = containmentEdges[toNodeFieldIndex] / nodeFieldCount;
  3894. affected[nodeOrdinal2PostOrderIndex[childNodeOrdinal]] = 1;
  3895. }
  3896. }
  3897.  
  3898. var changed = true;
  3899. while (changed) {
  3900. changed = false;
  3901. for (var postOrderIndex = rootPostOrderedIndex - 1; postOrderIndex >= 0; --postOrderIndex) {
  3902. if (affected[postOrderIndex] === 0)
  3903. continue;
  3904. affected[postOrderIndex] = 0;
  3905.  
  3906.  
  3907. if (dominators[postOrderIndex] === rootPostOrderedIndex)
  3908. continue;
  3909. nodeOrdinal = postOrderIndex2NodeOrdinal[postOrderIndex];
  3910. var nodeFlag = !!(flags[nodeOrdinal] & flag);
  3911. var newDominatorIndex = noEntry;
  3912. var beginRetainerIndex = firstRetainerIndex[nodeOrdinal];
  3913. var endRetainerIndex = firstRetainerIndex[nodeOrdinal + 1];
  3914. for (var retainerIndex = beginRetainerIndex; retainerIndex < endRetainerIndex; ++retainerIndex) {
  3915. var retainerEdgeIndex = retainingEdges[retainerIndex];
  3916. var retainerEdgeType = containmentEdges[retainerEdgeIndex + edgeTypeOffset];
  3917. var retainerNodeIndex = retainingNodes[retainerIndex];
  3918. if (retainerNodeIndex !== rootNodeIndex && retainerEdgeType === edgeShortcutType)
  3919. continue;
  3920. var retainerNodeOrdinal = retainerNodeIndex / nodeFieldCount;
  3921. var retainerNodeFlag = !!(flags[retainerNodeOrdinal] & flag);
  3922.  
  3923.  
  3924. if (retainerNodeIndex !== rootNodeIndex && nodeFlag && !retainerNodeFlag)
  3925. continue;
  3926. var retanerPostOrderIndex = nodeOrdinal2PostOrderIndex[retainerNodeOrdinal];
  3927. if (dominators[retanerPostOrderIndex] !== noEntry) {
  3928. if (newDominatorIndex === noEntry)
  3929. newDominatorIndex = retanerPostOrderIndex;
  3930. else {
  3931. while (retanerPostOrderIndex !== newDominatorIndex) {
  3932. while (retanerPostOrderIndex < newDominatorIndex)
  3933. retanerPostOrderIndex = dominators[retanerPostOrderIndex];
  3934. while (newDominatorIndex < retanerPostOrderIndex)
  3935. newDominatorIndex = dominators[newDominatorIndex];
  3936. }
  3937. }
  3938.  
  3939.  
  3940. if (newDominatorIndex === rootPostOrderedIndex)
  3941. break;
  3942. }
  3943. }
  3944. if (newDominatorIndex !== noEntry && dominators[postOrderIndex] !== newDominatorIndex) {
  3945. dominators[postOrderIndex] = newDominatorIndex;
  3946. changed = true;
  3947. nodeOrdinal = postOrderIndex2NodeOrdinal[postOrderIndex];
  3948. beginEdgeToNodeFieldIndex = firstEdgeIndexes[nodeOrdinal] + edgeToNodeOffset;
  3949. endEdgeToNodeFieldIndex = firstEdgeIndexes[nodeOrdinal + 1];
  3950. for (var toNodeFieldIndex = beginEdgeToNodeFieldIndex;
  3951. toNodeFieldIndex < endEdgeToNodeFieldIndex;
  3952. toNodeFieldIndex += edgeFieldsCount) {
  3953. var childNodeOrdinal = containmentEdges[toNodeFieldIndex] / nodeFieldCount;
  3954. affected[nodeOrdinal2PostOrderIndex[childNodeOrdinal]] = 1;
  3955. }
  3956. }
  3957. }
  3958. }
  3959.  
  3960. var dominatorsTree = new Uint32Array(nodesCount);
  3961. for (var postOrderIndex = 0, l = dominators.length; postOrderIndex < l; ++postOrderIndex) {
  3962. nodeOrdinal = postOrderIndex2NodeOrdinal[postOrderIndex];
  3963. dominatorsTree[nodeOrdinal] = postOrderIndex2NodeOrdinal[dominators[postOrderIndex]];
  3964. }
  3965. return dominatorsTree;
  3966. },
  3967.  
  3968. _calculateRetainedSizes: function(postOrderIndex2NodeOrdinal)
  3969. {
  3970. var nodeCount = this.nodeCount;
  3971. var nodes = this._nodes;
  3972. var nodeSelfSizeOffset = this._nodeSelfSizeOffset;
  3973. var nodeFieldCount = this._nodeFieldCount;
  3974. var dominatorsTree = this._dominatorsTree;
  3975.  
  3976. var nodeRetainedSizeOffset = this._nodeRetainedSizeOffset = this._nodeEdgeCountOffset;
  3977. delete this._nodeEdgeCountOffset;
  3978.  
  3979. for (var nodeIndex = 0, l = nodes.length; nodeIndex < l; nodeIndex += nodeFieldCount)
  3980. nodes[nodeIndex + nodeRetainedSizeOffset] = nodes[nodeIndex + nodeSelfSizeOffset];
  3981.  
  3982.  
  3983. for (var postOrderIndex = 0; postOrderIndex < nodeCount - 1; ++postOrderIndex) {
  3984. var nodeOrdinal = postOrderIndex2NodeOrdinal[postOrderIndex];
  3985. var nodeIndex = nodeOrdinal * nodeFieldCount;
  3986. var dominatorIndex = dominatorsTree[nodeOrdinal] * nodeFieldCount;
  3987. nodes[dominatorIndex + nodeRetainedSizeOffset] += nodes[nodeIndex + nodeRetainedSizeOffset];
  3988. }
  3989. },
  3990.  
  3991. _buildDominatedNodes: function()
  3992. {
  3993.  
  3994.  
  3995.  
  3996.  
  3997.  
  3998. var indexArray = this._firstDominatedNodeIndex = new Uint32Array(this.nodeCount + 1);
  3999.  
  4000. var dominatedNodes = this._dominatedNodes = new Uint32Array(this.nodeCount - 1);
  4001.  
  4002.  
  4003.  
  4004. var nodeFieldCount = this._nodeFieldCount;
  4005. var dominatorsTree = this._dominatorsTree;
  4006. for (var nodeOrdinal = 1, l = this.nodeCount; nodeOrdinal < l; ++nodeOrdinal)
  4007. ++indexArray[dominatorsTree[nodeOrdinal]];
  4008.  
  4009.  
  4010. var firstDominatedNodeIndex = 0;
  4011. for (var i = 0, l = this.nodeCount; i < l; ++i) {
  4012. var dominatedCount = dominatedNodes[firstDominatedNodeIndex] = indexArray[i];
  4013. indexArray[i] = firstDominatedNodeIndex;
  4014. firstDominatedNodeIndex += dominatedCount;
  4015. }
  4016. indexArray[this.nodeCount] = dominatedNodes.length;
  4017.  
  4018.  
  4019. for (var nodeOrdinal = 1, l = this.nodeCount; nodeOrdinal < l; ++nodeOrdinal) {
  4020. var dominatorOrdinal = dominatorsTree[nodeOrdinal];
  4021. var dominatedRefIndex = indexArray[dominatorOrdinal];
  4022. dominatedRefIndex += (--dominatedNodes[dominatedRefIndex]);
  4023. dominatedNodes[dominatedRefIndex] = nodeOrdinal * nodeFieldCount;
  4024. }
  4025. },
  4026.  
  4027. _markInvisibleEdges: function()
  4028. {
  4029.  
  4030.  
  4031.  
  4032. for (var iter = this.rootNode().edges(); iter.hasNext(); iter.next()) {
  4033. var edge = iter.edge;
  4034. if (!edge.isShortcut())
  4035. continue;
  4036. var node = edge.node();
  4037. var propNames = {};
  4038. for (var innerIter = node.edges(); innerIter.hasNext(); innerIter.next()) {
  4039. var globalObjEdge = innerIter.edge;
  4040. if (globalObjEdge.isShortcut())
  4041. propNames[globalObjEdge._nameOrIndex()] = true;
  4042. }
  4043. for (innerIter.first(); innerIter.hasNext(); innerIter.next()) {
  4044. var globalObjEdge = innerIter.edge;
  4045. if (!globalObjEdge.isShortcut()
  4046. && globalObjEdge.node().isHidden()
  4047. && globalObjEdge._hasStringName()
  4048. && (globalObjEdge._nameOrIndex() in propNames))
  4049. this._containmentEdges[globalObjEdge._edges._start + globalObjEdge.edgeIndex + this._edgeTypeOffset] = this._edgeInvisibleType;
  4050. }
  4051. }
  4052. },
  4053.  
  4054. _numbersComparator: function(a, b)
  4055. {
  4056. return a < b ? -1 : (a > b ? 1 : 0);
  4057. },
  4058.  
  4059. _markDetachedDOMTreeNodes: function()
  4060. {
  4061. var flag = this._nodeFlags.detachedDOMTreeNode;
  4062. var detachedDOMTreesRoot;
  4063. for (var iter = this.rootNode().edges(); iter.hasNext(); iter.next()) {
  4064. var node = iter.edge.node();
  4065. if (node.isDetachedDOMTreesRoot()) {
  4066. detachedDOMTreesRoot = node;
  4067. break;
  4068. }
  4069. }
  4070.  
  4071. if (!detachedDOMTreesRoot)
  4072. return;
  4073.  
  4074. for (var iter = detachedDOMTreesRoot.edges(); iter.hasNext(); iter.next()) {
  4075. var node = iter.edge.node();
  4076. if (node.isDetachedDOMTree()) {
  4077. for (var edgesIter = node.edges(); edgesIter.hasNext(); edgesIter.next())
  4078. this._flags[edgesIter.edge.node().nodeIndex / this._nodeFieldCount] |= flag;
  4079. }
  4080. }
  4081. },
  4082.  
  4083. _markPageOwnedNodes: function()
  4084. {
  4085. var edgeShortcutType = this._edgeShortcutType;
  4086. var edgeToNodeOffset = this._edgeToNodeOffset;
  4087. var edgeTypeOffset = this._edgeTypeOffset;
  4088. var edgeFieldsCount = this._edgeFieldsCount;
  4089. var edgeWeakType = this._edgeWeakType;
  4090. var firstEdgeIndexes = this._firstEdgeIndexes;
  4091. var containmentEdges = this._containmentEdges;
  4092. var containmentEdgesLength = containmentEdges.length;
  4093. var nodes = this._nodes;
  4094. var nodeFieldCount = this._nodeFieldCount;
  4095. var nodesCount = this.nodeCount;
  4096.  
  4097. var flags = this._flags;
  4098. var flag = this._nodeFlags.pageObject;
  4099. var visitedMarker = this._nodeFlags.visitedMarker;
  4100. var visitedMarkerMask = this._nodeFlags.visitedMarkerMask;
  4101. var markerAndFlag = visitedMarker | flag;
  4102.  
  4103. var nodesToVisit = new Uint32Array(nodesCount);
  4104. var nodesToVisitLength = 0;
  4105.  
  4106. var rootNodeOrdinal = this._rootNodeIndex / nodeFieldCount;
  4107. for (var edgeIndex = firstEdgeIndexes[rootNodeOrdinal], endEdgeIndex = firstEdgeIndexes[rootNodeOrdinal + 1];
  4108. edgeIndex < endEdgeIndex;
  4109. edgeIndex += edgeFieldsCount) {
  4110. if (containmentEdges[edgeIndex + edgeTypeOffset] === edgeShortcutType) {
  4111. var nodeOrdinal = containmentEdges[edgeIndex + edgeToNodeOffset] / nodeFieldCount;
  4112. nodesToVisit[nodesToVisitLength++] = nodeOrdinal;
  4113. flags[nodeOrdinal] |= visitedMarker;
  4114. }
  4115. }
  4116.  
  4117. while (nodesToVisitLength) {
  4118. var nodeOrdinal = nodesToVisit[--nodesToVisitLength];
  4119. flags[nodeOrdinal] |= flag;
  4120. flags[nodeOrdinal] &= visitedMarkerMask;
  4121. var beginEdgeIndex = firstEdgeIndexes[nodeOrdinal];
  4122. var endEdgeIndex = firstEdgeIndexes[nodeOrdinal + 1];
  4123. for (var edgeIndex = beginEdgeIndex; edgeIndex < endEdgeIndex; edgeIndex += edgeFieldsCount) {
  4124. var childNodeIndex = containmentEdges[edgeIndex + edgeToNodeOffset];
  4125. var childNodeOrdinal = childNodeIndex / nodeFieldCount;
  4126. if (flags[childNodeOrdinal] & markerAndFlag)
  4127. continue;
  4128. var type = containmentEdges[edgeIndex + edgeTypeOffset];
  4129. if (type === edgeWeakType)
  4130. continue;
  4131. nodesToVisit[nodesToVisitLength++] = childNodeOrdinal;
  4132. flags[childNodeOrdinal] |= visitedMarker;
  4133. }
  4134. }
  4135. },
  4136.  
  4137. _markQueriableHeapObjects: function()
  4138. {
  4139.  
  4140.  
  4141.  
  4142. var flag = this._nodeFlags.canBeQueried;
  4143. var hiddenEdgeType = this._edgeHiddenType;
  4144. var internalEdgeType = this._edgeInternalType;
  4145. var invisibleEdgeType = this._edgeInvisibleType;
  4146. var weakEdgeType = this._edgeWeakType;
  4147. var edgeToNodeOffset = this._edgeToNodeOffset;
  4148. var edgeTypeOffset = this._edgeTypeOffset;
  4149. var edgeFieldsCount = this._edgeFieldsCount;
  4150. var containmentEdges = this._containmentEdges;
  4151. var nodes = this._nodes;
  4152. var nodeCount = this.nodeCount;
  4153. var nodeFieldCount = this._nodeFieldCount;
  4154. var firstEdgeIndexes = this._firstEdgeIndexes;
  4155.  
  4156. var flags = this._flags;
  4157. var list = [];
  4158.  
  4159. for (var iter = this.rootNode().edges(); iter.hasNext(); iter.next()) {
  4160. if (iter.edge.node().isWindow())
  4161. list.push(iter.edge.node().nodeIndex / nodeFieldCount);
  4162. }
  4163.  
  4164. while (list.length) {
  4165. var nodeOrdinal = list.pop();
  4166. if (flags[nodeOrdinal] & flag)
  4167. continue;
  4168. flags[nodeOrdinal] |= flag;
  4169. var beginEdgeIndex = firstEdgeIndexes[nodeOrdinal];
  4170. var endEdgeIndex = firstEdgeIndexes[nodeOrdinal + 1];
  4171. for (var edgeIndex = beginEdgeIndex; edgeIndex < endEdgeIndex; edgeIndex += edgeFieldsCount) {
  4172. var childNodeIndex = containmentEdges[edgeIndex + edgeToNodeOffset];
  4173. var childNodeOrdinal = childNodeIndex / nodeFieldCount;
  4174. if (flags[childNodeOrdinal] & flag)
  4175. continue;
  4176. var type = containmentEdges[edgeIndex + edgeTypeOffset];
  4177. if (type === hiddenEdgeType || type === invisibleEdgeType || type === internalEdgeType || type === weakEdgeType)
  4178. continue;
  4179. list.push(childNodeOrdinal);
  4180. }
  4181. }
  4182. },
  4183.  
  4184. _calculateFlags: function()
  4185. {
  4186. this._flags = new Uint32Array(this.nodeCount);
  4187. this._markDetachedDOMTreeNodes();
  4188. this._markQueriableHeapObjects();
  4189. this._markPageOwnedNodes();
  4190. },
  4191.  
  4192. calculateSnapshotDiff: function(baseSnapshotId, baseSnapshotAggregates)
  4193. {
  4194. var snapshotDiff = this._snapshotDiffs[baseSnapshotId];
  4195. if (snapshotDiff)
  4196. return snapshotDiff;
  4197. snapshotDiff = {};
  4198.  
  4199. var aggregates = this.aggregates(true, "allObjects");
  4200. for (var className in baseSnapshotAggregates) {
  4201. var baseAggregate = baseSnapshotAggregates[className];
  4202. var diff = this._calculateDiffForClass(baseAggregate, aggregates[className]);
  4203. if (diff)
  4204. snapshotDiff[className] = diff;
  4205. }
  4206. var emptyBaseAggregate = { ids: [], indexes: [], selfSizes: [] };
  4207. for (var className in aggregates) {
  4208. if (className in baseSnapshotAggregates)
  4209. continue;
  4210. snapshotDiff[className] = this._calculateDiffForClass(emptyBaseAggregate, aggregates[className]);
  4211. }
  4212.  
  4213. this._snapshotDiffs[baseSnapshotId] = snapshotDiff;
  4214. return snapshotDiff;
  4215. },
  4216.  
  4217. _calculateDiffForClass: function(baseAggregate, aggregate)
  4218. {
  4219. var baseIds = baseAggregate.ids;
  4220. var baseIndexes = baseAggregate.indexes;
  4221. var baseSelfSizes = baseAggregate.selfSizes;
  4222.  
  4223. var indexes = aggregate ? aggregate.idxs : [];
  4224.  
  4225. var i = 0, l = baseIds.length;
  4226. var j = 0, m = indexes.length;
  4227. var diff = { addedCount: 0,
  4228. removedCount: 0,
  4229. addedSize: 0,
  4230. removedSize: 0,
  4231. deletedIndexes: [],
  4232. addedIndexes: [] };
  4233.  
  4234. var nodeB = new WebInspector.HeapSnapshotNode(this, indexes[j]);
  4235. while (i < l && j < m) {
  4236. var nodeAId = baseIds[i];
  4237. if (nodeAId < nodeB.id()) {
  4238. diff.deletedIndexes.push(baseIndexes[i]);
  4239. diff.removedCount++;
  4240. diff.removedSize += baseSelfSizes[i];
  4241. ++i;
  4242. } else if (nodeAId > nodeB.id()) { 
  4243. diff.addedIndexes.push(indexes[j]);
  4244. diff.addedCount++;
  4245. diff.addedSize += nodeB.selfSize();
  4246. nodeB.nodeIndex = indexes[++j];
  4247. } else { 
  4248. ++i;
  4249. nodeB.nodeIndex = indexes[++j];
  4250. }
  4251. }
  4252. while (i < l) {
  4253. diff.deletedIndexes.push(baseIndexes[i]);
  4254. diff.removedCount++;
  4255. diff.removedSize += baseSelfSizes[i];
  4256. ++i;
  4257. }
  4258. while (j < m) {
  4259. diff.addedIndexes.push(indexes[j]);
  4260. diff.addedCount++;
  4261. diff.addedSize += nodeB.selfSize();
  4262. nodeB.nodeIndex = indexes[++j];
  4263. }
  4264. diff.countDelta = diff.addedCount - diff.removedCount;
  4265. diff.sizeDelta = diff.addedSize - diff.removedSize;
  4266. if (!diff.addedCount && !diff.removedCount)
  4267. return null;
  4268. return diff;
  4269. },
  4270.  
  4271. _nodeForSnapshotObjectId: function(snapshotObjectId)
  4272. {
  4273. for (var it = this._allNodes(); it.hasNext(); it.next()) {
  4274. if (it.node.id() === snapshotObjectId)
  4275. return it.node;
  4276. }
  4277. return null;
  4278. },
  4279.  
  4280. nodeClassName: function(snapshotObjectId)
  4281. {
  4282. var node = this._nodeForSnapshotObjectId(snapshotObjectId);
  4283. if (node)
  4284. return node.className();
  4285. return null;
  4286. },
  4287.  
  4288. dominatorIdsForNode: function(snapshotObjectId)
  4289. {
  4290. var node = this._nodeForSnapshotObjectId(snapshotObjectId);
  4291. if (!node)
  4292. return null;
  4293. var result = [];
  4294. while (!node.isRoot()) {
  4295. result.push(node.id());
  4296. node.nodeIndex = node.dominatorIndex();
  4297. }
  4298. return result;
  4299. },
  4300.  
  4301. _parseFilter: function(filter)
  4302. {
  4303. if (!filter)
  4304. return null;
  4305. var parsedFilter = eval("(function(){return " + filter + "})()");
  4306. return parsedFilter.bind(this);
  4307. },
  4308.  
  4309. createEdgesProvider: function(nodeIndex, filter)
  4310. {
  4311. var node = new WebInspector.HeapSnapshotNode(this, nodeIndex);
  4312. return new WebInspector.HeapSnapshotEdgesProvider(this, this._parseFilter(filter), node.edges());
  4313. },
  4314.  
  4315. createRetainingEdgesProvider: function(nodeIndex, filter)
  4316. {
  4317. var node = new WebInspector.HeapSnapshotNode(this, nodeIndex);
  4318. return new WebInspector.HeapSnapshotEdgesProvider(this, this._parseFilter(filter), node.retainers());
  4319. },
  4320.  
  4321. createAddedNodesProvider: function(baseSnapshotId, className)
  4322. {
  4323. var snapshotDiff = this._snapshotDiffs[baseSnapshotId];
  4324. var diffForClass = snapshotDiff[className];
  4325. return new WebInspector.HeapSnapshotNodesProvider(this, null, diffForClass.addedIndexes);
  4326. },
  4327.  
  4328. createDeletedNodesProvider: function(nodeIndexes)
  4329. {
  4330. return new WebInspector.HeapSnapshotNodesProvider(this, null, nodeIndexes);
  4331. },
  4332.  
  4333. createNodesProviderForClass: function(className, aggregatesKey)
  4334. {
  4335. function filter(node) {
  4336. return node.isPageObject();
  4337. }
  4338. return new WebInspector.HeapSnapshotNodesProvider(this, filter, this.aggregates(false, aggregatesKey)[className].idxs);
  4339. },
  4340.  
  4341. createNodesProviderForDominator: function(nodeIndex)
  4342. {
  4343. var node = new WebInspector.HeapSnapshotNode(this, nodeIndex);
  4344. return new WebInspector.HeapSnapshotNodesProvider(this, null, this._dominatedNodesOfNode(node));
  4345. },
  4346.  
  4347. updateStaticData: function()
  4348. {
  4349. return {nodeCount: this.nodeCount, rootNodeIndex: this._rootNodeIndex, totalSize: this.totalSize, uid: this.uid, nodeFlags: this._nodeFlags};
  4350. }
  4351. };
  4352.  
  4353.  
  4354. WebInspector.HeapSnapshotFilteredOrderedIterator = function(iterator, filter, unfilteredIterationOrder)
  4355. {
  4356. this._filter = filter;
  4357. this._iterator = iterator;
  4358. this._unfilteredIterationOrder = unfilteredIterationOrder;
  4359. this._iterationOrder = null;
  4360. this._position = 0;
  4361. this._currentComparator = null;
  4362. this._sortedPrefixLength = 0;
  4363. }
  4364.  
  4365. WebInspector.HeapSnapshotFilteredOrderedIterator.prototype = {
  4366. _createIterationOrder: function()
  4367. {
  4368. if (this._iterationOrder)
  4369. return;
  4370. if (this._unfilteredIterationOrder && !this._filter) {
  4371. this._iterationOrder = this._unfilteredIterationOrder.slice(0);
  4372. this._unfilteredIterationOrder = null;
  4373. return;
  4374. }
  4375. this._iterationOrder = [];
  4376. var iterator = this._iterator;
  4377. if (!this._unfilteredIterationOrder && !this._filter) {
  4378. for (iterator.first(); iterator.hasNext(); iterator.next())
  4379. this._iterationOrder.push(iterator.index());
  4380. } else if (!this._unfilteredIterationOrder) {
  4381. for (iterator.first(); iterator.hasNext(); iterator.next()) {
  4382. if (this._filter(iterator.item()))
  4383. this._iterationOrder.push(iterator.index());
  4384. }
  4385. } else {
  4386. var order = this._unfilteredIterationOrder.constructor === Array ?
  4387. this._unfilteredIterationOrder : this._unfilteredIterationOrder.slice(0);
  4388. for (var i = 0, l = order.length; i < l; ++i) {
  4389. iterator.setIndex(order[i]);
  4390. if (this._filter(iterator.item()))
  4391. this._iterationOrder.push(iterator.index());
  4392. }
  4393. this._unfilteredIterationOrder = null;
  4394. }
  4395. },
  4396.  
  4397. first: function()
  4398. {
  4399. this._position = 0;
  4400. },
  4401.  
  4402. hasNext: function()
  4403. {
  4404. return this._position < this._iterationOrder.length;
  4405. },
  4406.  
  4407. isEmpty: function()
  4408. {
  4409. if (this._iterationOrder)
  4410. return !this._iterationOrder.length;
  4411. if (this._unfilteredIterationOrder && !this._filter)
  4412. return !this._unfilteredIterationOrder.length;
  4413. var iterator = this._iterator;
  4414. if (!this._unfilteredIterationOrder && !this._filter) {
  4415. iterator.first();
  4416. return !iterator.hasNext();
  4417. } else if (!this._unfilteredIterationOrder) {
  4418. for (iterator.first(); iterator.hasNext(); iterator.next())
  4419. if (this._filter(iterator.item()))
  4420. return false;
  4421. } else {
  4422. var order = this._unfilteredIterationOrder.constructor === Array ?
  4423. this._unfilteredIterationOrder : this._unfilteredIterationOrder.slice(0);
  4424. for (var i = 0, l = order.length; i < l; ++i) {
  4425. iterator.setIndex(order[i]);
  4426. if (this._filter(iterator.item()))
  4427. return false;
  4428. }
  4429. }
  4430. return true;
  4431. },
  4432.  
  4433. item: function()
  4434. {
  4435. this._iterator.setIndex(this._iterationOrder[this._position]);
  4436. return this._iterator.item();
  4437. },
  4438.  
  4439. get length()
  4440. {
  4441. this._createIterationOrder();
  4442. return this._iterationOrder.length;
  4443. },
  4444.  
  4445. next: function()
  4446. {
  4447. ++this._position;
  4448. },
  4449.  
  4450.  
  4451. serializeItemsRange: function(begin, end)
  4452. {
  4453. this._createIterationOrder();
  4454. if (begin > end)
  4455. throw new Error("Start position > end position: " + begin + " > " + end);
  4456. if (end >= this._iterationOrder.length)
  4457. end = this._iterationOrder.length;
  4458. if (this._sortedPrefixLength < end) {
  4459. this.sort(this._currentComparator, this._sortedPrefixLength, this._iterationOrder.length - 1, end - this._sortedPrefixLength);
  4460. this._sortedPrefixLength = end;
  4461. }
  4462.  
  4463. this._position = begin;
  4464. var startPosition = this._position;
  4465. var count = end - begin;
  4466. var result = new Array(count);
  4467. for (var i = 0 ; i < count && this.hasNext(); ++i, this.next())
  4468. result[i] = this.serializeItem(this.item());
  4469. result.length = i;
  4470. result.totalLength = this._iterationOrder.length;
  4471.  
  4472. result.startPosition = startPosition;
  4473. result.endPosition = this._position;
  4474. return result;
  4475. },
  4476.  
  4477. sortAll: function()
  4478. {
  4479. this._createIterationOrder();
  4480. if (this._sortedPrefixLength === this._iterationOrder.length)
  4481. return;
  4482. this.sort(this._currentComparator, this._sortedPrefixLength, this._iterationOrder.length - 1, this._iterationOrder.length);
  4483. this._sortedPrefixLength = this._iterationOrder.length;
  4484. },
  4485.  
  4486. sortAndRewind: function(comparator)
  4487. {
  4488. this._currentComparator = comparator;
  4489. this._sortedPrefixLength = 0;
  4490. this.first();
  4491. }
  4492. }
  4493.  
  4494. WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator = function(fieldNames)
  4495. {
  4496. return {fieldName1:fieldNames[0], ascending1:fieldNames[1], fieldName2:fieldNames[2], ascending2:fieldNames[3]};
  4497. }
  4498.  
  4499.  
  4500. WebInspector.HeapSnapshotEdgesProvider = function(snapshot, filter, edgesIter)
  4501. {
  4502. this.snapshot = snapshot;
  4503. WebInspector.HeapSnapshotFilteredOrderedIterator.call(this, edgesIter, filter);
  4504. }
  4505.  
  4506. WebInspector.HeapSnapshotEdgesProvider.prototype = {
  4507. serializeItem: function(edge)
  4508. {
  4509. return {
  4510. name: edge.name(),
  4511. propertyAccessor: edge.toString(),
  4512. node: WebInspector.HeapSnapshotNodesProvider.prototype.serializeItem(edge.node()),
  4513. nodeIndex: edge.nodeIndex(),
  4514. type: edge.type(),
  4515. distanceToWindow: edge.node().distanceToWindow()
  4516. };
  4517. },
  4518.  
  4519. sort: function(comparator, leftBound, rightBound, count)
  4520. {
  4521. var fieldName1 = comparator.fieldName1;
  4522. var fieldName2 = comparator.fieldName2;
  4523. var ascending1 = comparator.ascending1;
  4524. var ascending2 = comparator.ascending2;
  4525.  
  4526. var edgeA = this._iterator.item().clone();
  4527. var edgeB = edgeA.clone();
  4528. var nodeA = new WebInspector.HeapSnapshotNode(this.snapshot);
  4529. var nodeB = new WebInspector.HeapSnapshotNode(this.snapshot);
  4530.  
  4531. function compareEdgeFieldName(ascending, indexA, indexB)
  4532. {
  4533. edgeA.edgeIndex = indexA;
  4534. edgeB.edgeIndex = indexB;
  4535. if (edgeB.name() === "__proto__") return -1;
  4536. if (edgeA.name() === "__proto__") return 1;
  4537. var result =
  4538. edgeA.hasStringName() === edgeB.hasStringName() ?
  4539. (edgeA.name() < edgeB.name() ? -1 : (edgeA.name() > edgeB.name() ? 1 : 0)) :
  4540. (edgeA.hasStringName() ? -1 : 1);
  4541. return ascending ? result : -result;
  4542. }
  4543.  
  4544. function compareNodeField(fieldName, ascending, indexA, indexB)
  4545. {
  4546. edgeA.edgeIndex = indexA;
  4547. nodeA.nodeIndex = edgeA.nodeIndex();
  4548. var valueA = nodeA[fieldName]();
  4549.  
  4550. edgeB.edgeIndex = indexB;
  4551. nodeB.nodeIndex = edgeB.nodeIndex();
  4552. var valueB = nodeB[fieldName]();
  4553.  
  4554. var result = valueA < valueB ? -1 : (valueA > valueB ? 1 : 0);
  4555. return ascending ? result : -result;
  4556. }
  4557.  
  4558. function compareEdgeAndNode(indexA, indexB) {
  4559. var result = compareEdgeFieldName(ascending1, indexA, indexB);
  4560. if (result === 0)
  4561. result = compareNodeField(fieldName2, ascending2, indexA, indexB);
  4562. return result;
  4563. }
  4564.  
  4565. function compareNodeAndEdge(indexA, indexB) {
  4566. var result = compareNodeField(fieldName1, ascending1, indexA, indexB);
  4567. if (result === 0)
  4568. result = compareEdgeFieldName(ascending2, indexA, indexB);
  4569. return result;
  4570. }
  4571.  
  4572. function compareNodeAndNode(indexA, indexB) {
  4573. var result = compareNodeField(fieldName1, ascending1, indexA, indexB);
  4574. if (result === 0)
  4575. result = compareNodeField(fieldName2, ascending2, indexA, indexB);
  4576. return result;
  4577. }
  4578.  
  4579. if (fieldName1 === "!edgeName")
  4580. this._iterationOrder.sortRange(compareEdgeAndNode, leftBound, rightBound, count);
  4581. else if (fieldName2 === "!edgeName")
  4582. this._iterationOrder.sortRange(compareNodeAndEdge, leftBound, rightBound, count);
  4583. else
  4584. this._iterationOrder.sortRange(compareNodeAndNode, leftBound, rightBound, count);
  4585. },
  4586.  
  4587. __proto__: WebInspector.HeapSnapshotFilteredOrderedIterator.prototype
  4588. }
  4589.  
  4590.  
  4591.  
  4592. WebInspector.HeapSnapshotNodesProvider = function(snapshot, filter, nodeIndexes)
  4593. {
  4594. this.snapshot = snapshot;
  4595. WebInspector.HeapSnapshotFilteredOrderedIterator.call(this, snapshot._allNodes(), filter, nodeIndexes);
  4596. }
  4597.  
  4598. WebInspector.HeapSnapshotNodesProvider.prototype = {
  4599. nodePosition: function(snapshotObjectId)
  4600. {
  4601. this._createIterationOrder();
  4602. if (this.isEmpty())
  4603. return -1;
  4604. this.sortAll();
  4605.  
  4606. var node = new WebInspector.HeapSnapshotNode(this.snapshot);
  4607. for (var i = 0; i < this._iterationOrder.length; i++) {
  4608. node.nodeIndex = this._iterationOrder[i];
  4609. if (node.id() === snapshotObjectId)
  4610. return i;
  4611. }
  4612. return -1;
  4613. },
  4614.  
  4615. serializeItem: function(node)
  4616. {
  4617. return {
  4618. id: node.id(),
  4619. name: node.name(),
  4620. distanceToWindow: node.distanceToWindow(),
  4621. nodeIndex: node.nodeIndex,
  4622. retainedSize: node.retainedSize(),
  4623. selfSize: node.selfSize(),
  4624. type: node.type(),
  4625. flags: node.flags()
  4626. };
  4627. },
  4628.  
  4629. sort: function(comparator, leftBound, rightBound, count)
  4630. {
  4631. var fieldName1 = comparator.fieldName1;
  4632. var fieldName2 = comparator.fieldName2;
  4633. var ascending1 = comparator.ascending1;
  4634. var ascending2 = comparator.ascending2;
  4635.  
  4636. var nodeA = new WebInspector.HeapSnapshotNode(this.snapshot);
  4637. var nodeB = new WebInspector.HeapSnapshotNode(this.snapshot);
  4638.  
  4639. function sortByNodeField(fieldName, ascending)
  4640. {
  4641. var valueOrFunctionA = nodeA[fieldName];
  4642. var valueA = typeof valueOrFunctionA !== "function" ? valueOrFunctionA : valueOrFunctionA.call(nodeA);
  4643. var valueOrFunctionB = nodeB[fieldName];
  4644. var valueB = typeof valueOrFunctionB !== "function" ? valueOrFunctionB : valueOrFunctionB.call(nodeB);
  4645. var result = valueA < valueB ? -1 : (valueA > valueB ? 1 : 0);
  4646. return ascending ? result : -result;
  4647. }
  4648.  
  4649. function sortByComparator(indexA, indexB) {
  4650. nodeA.nodeIndex = indexA;
  4651. nodeB.nodeIndex = indexB;
  4652. var result = sortByNodeField(fieldName1, ascending1);
  4653. if (result === 0)
  4654. result = sortByNodeField(fieldName2, ascending2);
  4655. return result;
  4656. }
  4657.  
  4658. this._iterationOrder.sortRange(sortByComparator, leftBound, rightBound, count);
  4659. },
  4660.  
  4661. __proto__: WebInspector.HeapSnapshotFilteredOrderedIterator.prototype
  4662. }
  4663.  
  4664. ;
  4665.  
  4666.  
  4667.  
  4668. WebInspector.HeapSnapshotSortableDataGrid = function(columns)
  4669. {
  4670. WebInspector.DataGrid.call(this, columns);
  4671.  
  4672.  
  4673. this._recursiveSortingDepth = 0;
  4674.  
  4675. this._highlightedNode = null;
  4676.  
  4677. this._populatedAndSorted = false;
  4678. this.addEventListener("sorting complete", this._sortingComplete, this);
  4679. this.addEventListener("sorting changed", this.sortingChanged, this);
  4680. }
  4681.  
  4682. WebInspector.HeapSnapshotSortableDataGrid.Events = {
  4683. ContentShown: "ContentShown"
  4684. }
  4685.  
  4686. WebInspector.HeapSnapshotSortableDataGrid.prototype = {
  4687.  
  4688. defaultPopulateCount: function()
  4689. {
  4690. return 100;
  4691. },
  4692.  
  4693. dispose: function()
  4694. {
  4695. var children = this.topLevelNodes();
  4696. for (var i = 0, l = children.length; i < l; ++i)
  4697. children[i].dispose();
  4698. },
  4699.  
  4700.  
  4701. wasShown: function()
  4702. {
  4703. if (this._populatedAndSorted)
  4704. this.dispatchEventToListeners(WebInspector.HeapSnapshotSortableDataGrid.Events.ContentShown, this);
  4705. },
  4706.  
  4707. _sortingComplete: function()
  4708. {
  4709. this.removeEventListener("sorting complete", this._sortingComplete, this);
  4710. this._populatedAndSorted = true;
  4711. this.dispatchEventToListeners(WebInspector.HeapSnapshotSortableDataGrid.Events.ContentShown, this);
  4712. },
  4713.  
  4714.  
  4715. willHide: function()
  4716. {
  4717. this._clearCurrentHighlight();
  4718. },
  4719.  
  4720.  
  4721. populateContextMenu: function(profilesPanel, contextMenu, event)
  4722. {
  4723. var td = event.target.enclosingNodeOrSelfWithNodeName("td");
  4724. if (!td)
  4725. return;
  4726. var node = td.heapSnapshotNode;
  4727. if (node instanceof WebInspector.HeapSnapshotInstanceNode || node instanceof WebInspector.HeapSnapshotObjectNode) {
  4728. function revealInDominatorsView()
  4729. {
  4730. profilesPanel.showObject(node.snapshotNodeId, "Dominators");
  4731. }
  4732. contextMenu.appendItem(WebInspector.UIString("Reveal in Dominators View"), revealInDominatorsView.bind(this));
  4733. } else if (node instanceof WebInspector.HeapSnapshotDominatorObjectNode) {
  4734. function revealInSummaryView()
  4735. {
  4736. profilesPanel.showObject(node.snapshotNodeId, "Summary");
  4737. }
  4738. contextMenu.appendItem(WebInspector.UIString("Reveal in Summary View"), revealInSummaryView.bind(this));
  4739. }
  4740. },
  4741.  
  4742. resetSortingCache: function()
  4743. {
  4744. delete this._lastSortColumnIdentifier;
  4745. delete this._lastSortAscending;
  4746. },
  4747.  
  4748. topLevelNodes: function()
  4749. {
  4750. return this.rootNode().children;
  4751. },
  4752.  
  4753.  
  4754. highlightObjectByHeapSnapshotId: function(heapSnapshotObjectId)
  4755. {
  4756. },
  4757.  
  4758.  
  4759. highlightNode: function(node)
  4760. {
  4761. var prevNode = this._highlightedNode;
  4762. this._clearCurrentHighlight();
  4763. this._highlightedNode = node;
  4764. this._highlightedNode.element.addStyleClass("highlighted-row");
  4765.  
  4766. if (node === prevNode) {
  4767. var element = node.element;
  4768. var parent = element.parentElement;
  4769. var nextSibling = element.nextSibling;
  4770. parent.removeChild(element);
  4771. parent.insertBefore(element, nextSibling);
  4772. }
  4773. },
  4774.  
  4775. nodeWasDetached: function(node)
  4776. {
  4777. if (this._highlightedNode === node)
  4778. this._clearCurrentHighlight();
  4779. },
  4780.  
  4781. _clearCurrentHighlight: function()
  4782. {
  4783. if (!this._highlightedNode)
  4784. return
  4785. this._highlightedNode.element.removeStyleClass("highlighted-row");
  4786. this._highlightedNode = null;
  4787. },
  4788.  
  4789. changeNameFilter: function(filter)
  4790. {
  4791. filter = filter.toLowerCase();
  4792. var children = this.topLevelNodes();
  4793. for (var i = 0, l = children.length; i < l; ++i) {
  4794. var node = children[i];
  4795. if (node.depth === 0)
  4796. node.revealed = node._name.toLowerCase().indexOf(filter) !== -1;
  4797. }
  4798. this.updateVisibleNodes();
  4799. },
  4800.  
  4801. sortingChanged: function()
  4802. {
  4803. var sortAscending = this.sortOrder === "ascending";
  4804. var sortColumnIdentifier = this.sortColumnIdentifier;
  4805. if (this._lastSortColumnIdentifier === sortColumnIdentifier && this._lastSortAscending === sortAscending)
  4806. return;
  4807. this._lastSortColumnIdentifier = sortColumnIdentifier;
  4808. this._lastSortAscending = sortAscending;
  4809. var sortFields = this._sortFields(sortColumnIdentifier, sortAscending);
  4810.  
  4811. function SortByTwoFields(nodeA, nodeB)
  4812. {
  4813. var field1 = nodeA[sortFields[0]];
  4814. var field2 = nodeB[sortFields[0]];
  4815. var result = field1 < field2 ? -1 : (field1 > field2 ? 1 : 0);
  4816. if (!sortFields[1])
  4817. result = -result;
  4818. if (result !== 0)
  4819. return result;
  4820. field1 = nodeA[sortFields[2]];
  4821. field2 = nodeB[sortFields[2]];
  4822. result = field1 < field2 ? -1 : (field1 > field2 ? 1 : 0);
  4823. if (!sortFields[3])
  4824. result = -result;
  4825. return result;
  4826. }
  4827. this._performSorting(SortByTwoFields);
  4828. },
  4829.  
  4830. _performSorting: function(sortFunction)
  4831. {
  4832. this.recursiveSortingEnter();
  4833. var children = this._topLevelNodes;
  4834. this.rootNode().removeChildren();
  4835. children.sort(sortFunction);
  4836. for (var i = 0, l = children.length; i < l; ++i) {
  4837. var child = children[i];
  4838. this.appendChildAfterSorting(child);
  4839. if (child.expanded)
  4840. child.sort();
  4841. }
  4842. this.updateVisibleNodes();
  4843. this.recursiveSortingLeave();
  4844. },
  4845.  
  4846. appendChildAfterSorting: function(child)
  4847. {
  4848. var revealed = child.revealed;
  4849. this.rootNode().appendChild(child);
  4850. child.revealed = revealed;
  4851. },
  4852.  
  4853. updateVisibleNodes: function()
  4854. {
  4855. },
  4856.  
  4857. recursiveSortingEnter: function()
  4858. {
  4859. ++this._recursiveSortingDepth;
  4860. },
  4861.  
  4862. recursiveSortingLeave: function()
  4863. {
  4864. if (!this._recursiveSortingDepth)
  4865. return;
  4866. if (!--this._recursiveSortingDepth)
  4867. this.dispatchEventToListeners("sorting complete");
  4868. },
  4869.  
  4870. __proto__: WebInspector.DataGrid.prototype
  4871. }
  4872.  
  4873.  
  4874.  
  4875.  
  4876. WebInspector.HeapSnapshotViewportDataGrid = function(columns)
  4877. {
  4878. WebInspector.HeapSnapshotSortableDataGrid.call(this, columns);
  4879. this.scrollContainer.addEventListener("scroll", this._onScroll.bind(this), true);
  4880. this._topLevelNodes = [];
  4881. this._topPadding = new WebInspector.HeapSnapshotPaddingNode();
  4882. this._bottomPadding = new WebInspector.HeapSnapshotPaddingNode();
  4883.  
  4884. this._nodeToHighlightAfterScroll = null;
  4885. }
  4886.  
  4887. WebInspector.HeapSnapshotViewportDataGrid.prototype = {
  4888. topLevelNodes: function()
  4889. {
  4890. return this._topLevelNodes;
  4891. },
  4892.  
  4893. appendChildAfterSorting: function(child)
  4894. {
  4895.  
  4896. },
  4897.  
  4898. updateVisibleNodes: function()
  4899. {
  4900. var scrollTop = this.scrollContainer.scrollTop;
  4901.  
  4902. var viewPortHeight = this.scrollContainer.offsetHeight;
  4903.  
  4904. this._removePaddingRows();
  4905.  
  4906. var children = this._topLevelNodes;
  4907.  
  4908. var i = 0;
  4909. var topPadding = 0;
  4910. while (i < children.length) {
  4911. if (children[i].revealed) {
  4912. var newTop = topPadding + children[i].nodeHeight();
  4913. if (newTop > scrollTop)
  4914. break;
  4915. topPadding = newTop;
  4916. }
  4917. ++i;
  4918. }
  4919.  
  4920. this.rootNode().removeChildren();
  4921.  
  4922. var heightToFill = viewPortHeight + (scrollTop - topPadding);
  4923. var filledHeight = 0;
  4924. while (i < children.length && filledHeight < heightToFill) {
  4925. if (children[i].revealed) {
  4926. this.rootNode().appendChild(children[i]);
  4927. filledHeight += children[i].nodeHeight();
  4928. }
  4929. ++i;
  4930. }
  4931.  
  4932. var bottomPadding = 0;
  4933. while (i < children.length) {
  4934. bottomPadding += children[i].nodeHeight();
  4935. ++i;
  4936. }
  4937.  
  4938. this._addPaddingRows(topPadding, bottomPadding);
  4939. },
  4940.  
  4941. appendTopLevelNode: function(node)
  4942. {
  4943. this._topLevelNodes.push(node);
  4944. },
  4945.  
  4946. removeTopLevelNodes: function()
  4947. {
  4948. this.rootNode().removeChildren();
  4949. this._topLevelNodes = [];
  4950. },
  4951.  
  4952.  
  4953. highlightNode: function(node)
  4954. {
  4955. if (this._isScrolledIntoView(node.element))
  4956. WebInspector.HeapSnapshotSortableDataGrid.prototype.highlightNode.call(this, node);
  4957. else {
  4958. node.element.scrollIntoViewIfNeeded(true);
  4959. this._nodeToHighlightAfterScroll = node;
  4960. }
  4961. },
  4962.  
  4963. _isScrolledIntoView: function(element)
  4964. {
  4965. var viewportTop = this.scrollContainer.scrollTop;
  4966. var viewportBottom = viewportTop + this.scrollContainer.clientHeight;
  4967. var elemTop = element.offsetTop
  4968. var elemBottom = elemTop + element.offsetHeight;
  4969. return elemBottom <= viewportBottom && elemTop >= viewportTop;
  4970. },
  4971.  
  4972. _addPaddingRows: function(top, bottom)
  4973. {
  4974. if (this._topPadding.element.parentNode !== this.dataTableBody)
  4975. this.dataTableBody.insertBefore(this._topPadding.element, this.dataTableBody.firstChild);
  4976. if (this._bottomPadding.element.parentNode !== this.dataTableBody)
  4977. this.dataTableBody.insertBefore(this._bottomPadding.element, this.dataTableBody.lastChild);
  4978. this._topPadding.setHeight(top);
  4979. this._bottomPadding.setHeight(bottom);
  4980. },
  4981.  
  4982. _removePaddingRows: function()
  4983. {
  4984. this._bottomPadding.removeFromTable();
  4985. this._topPadding.removeFromTable();
  4986. },
  4987.  
  4988. onResize: function()
  4989. {
  4990. WebInspector.HeapSnapshotSortableDataGrid.prototype.onResize.call(this);
  4991. this.updateVisibleNodes();
  4992. },
  4993.  
  4994. _onScroll: function(event)
  4995. {
  4996. this.updateVisibleNodes();
  4997.  
  4998. if (this._nodeToHighlightAfterScroll) {
  4999. WebInspector.HeapSnapshotSortableDataGrid.prototype.highlightNode.call(this, this._nodeToHighlightAfterScroll);
  5000. this._nodeToHighlightAfterScroll = null;
  5001. }
  5002. },
  5003.  
  5004. __proto__: WebInspector.HeapSnapshotSortableDataGrid.prototype
  5005. }
  5006.  
  5007.  
  5008. WebInspector.HeapSnapshotPaddingNode = function()
  5009. {
  5010. this.element = document.createElement("tr");
  5011. this.element.addStyleClass("revealed");
  5012. }
  5013.  
  5014. WebInspector.HeapSnapshotPaddingNode.prototype = {
  5015. setHeight: function(height)
  5016. {
  5017. this.element.style.height = height + "px";
  5018. },
  5019. removeFromTable: function()
  5020. {
  5021. var parent = this.element.parentNode;
  5022. if (parent)
  5023. parent.removeChild(this.element);
  5024. }
  5025. }
  5026.  
  5027.  
  5028.  
  5029. WebInspector.HeapSnapshotContainmentDataGrid = function(columns)
  5030. {
  5031. columns = columns || {
  5032. object: { title: WebInspector.UIString("Object"), disclosure: true, sortable: true },
  5033. shallowSize: { title: WebInspector.UIString("Shallow Size"), width: "120px", sortable: true },
  5034. retainedSize: { title: WebInspector.UIString("Retained Size"), width: "120px", sortable: true, sort: "descending" }
  5035. };
  5036. WebInspector.HeapSnapshotSortableDataGrid.call(this, columns);
  5037. }
  5038.  
  5039. WebInspector.HeapSnapshotContainmentDataGrid.prototype = {
  5040. setDataSource: function(snapshotView, snapshot, nodeIndex)
  5041. {
  5042. this.snapshotView = snapshotView;
  5043. this.snapshot = snapshot;
  5044. var node = new WebInspector.HeapSnapshotNode(snapshot, nodeIndex || snapshot.rootNodeIndex);
  5045. var fakeEdge = { node: node };
  5046. this.setRootNode(new WebInspector.HeapSnapshotObjectNode(this, false, fakeEdge, null));
  5047. this.rootNode().sort();
  5048. },
  5049.  
  5050. sortingChanged: function()
  5051. {
  5052. this.rootNode().sort();
  5053. },
  5054.  
  5055. __proto__: WebInspector.HeapSnapshotSortableDataGrid.prototype
  5056. }
  5057.  
  5058.  
  5059.  
  5060. WebInspector.HeapSnapshotRetainmentDataGrid = function()
  5061. {
  5062. this.showRetainingEdges = true;
  5063. var columns = {
  5064. object: { title: WebInspector.UIString("Object"), disclosure: true, sortable: true },
  5065. shallowSize: { title: WebInspector.UIString("Shallow Size"), width: "120px", sortable: true },
  5066. retainedSize: { title: WebInspector.UIString("Retained Size"), width: "120px", sortable: true },
  5067. distanceToWindow: { title: WebInspector.UIString("Distance"), width: "80px", sortable: true, sort: "ascending" }
  5068. };
  5069. WebInspector.HeapSnapshotContainmentDataGrid.call(this, columns);
  5070. }
  5071.  
  5072. WebInspector.HeapSnapshotRetainmentDataGrid.prototype = {
  5073. _sortFields: function(sortColumn, sortAscending)
  5074. {
  5075. return {
  5076. object: ["_name", sortAscending, "_count", false],
  5077. count: ["_count", sortAscending, "_name", true],
  5078. shallowSize: ["_shallowSize", sortAscending, "_name", true],
  5079. retainedSize: ["_retainedSize", sortAscending, "_name", true],
  5080. distanceToWindow: ["_distanceToWindow", sortAscending, "_name", true]
  5081. }[sortColumn];
  5082. },
  5083.  
  5084. reset: function()
  5085. {
  5086. this.rootNode().removeChildren();
  5087. this.resetSortingCache();
  5088. },
  5089.  
  5090. __proto__: WebInspector.HeapSnapshotContainmentDataGrid.prototype
  5091. }
  5092.  
  5093.  
  5094.  
  5095. WebInspector.HeapSnapshotConstructorsDataGrid = function()
  5096. {
  5097. var columns = {
  5098. object: { title: WebInspector.UIString("Constructor"), disclosure: true, sortable: true },
  5099. distanceToWindow: { title: WebInspector.UIString("Distance"), width: "90px", sortable: true },
  5100. count: { title: WebInspector.UIString("Objects Count"), width: "90px", sortable: true },
  5101. shallowSize: { title: WebInspector.UIString("Shallow Size"), width: "120px", sortable: true },
  5102. retainedSize: { title: WebInspector.UIString("Retained Size"), width: "120px", sort: "descending", sortable: true }
  5103. };
  5104. WebInspector.HeapSnapshotViewportDataGrid.call(this, columns);
  5105. this._profileIndex = -1;
  5106. this._topLevelNodes = [];
  5107.  
  5108. this._objectIdToSelect = null;
  5109. }
  5110.  
  5111. WebInspector.HeapSnapshotConstructorsDataGrid.prototype = {
  5112. _sortFields: function(sortColumn, sortAscending)
  5113. {
  5114. return {
  5115. object: ["_name", sortAscending, "_count", false],
  5116. distanceToWindow: ["_distanceToWindow", sortAscending, "_retainedSize", true],
  5117. count: ["_count", sortAscending, "_name", true],
  5118. shallowSize: ["_shallowSize", sortAscending, "_name", true],
  5119. retainedSize: ["_retainedSize", sortAscending, "_name", true]
  5120. }[sortColumn];
  5121. },
  5122.  
  5123.  
  5124. highlightObjectByHeapSnapshotId: function(id)
  5125. {
  5126. if (!this.snapshot) {
  5127. this._objectIdToSelect = id;
  5128. return;
  5129. }
  5130.  
  5131. function didGetClassName(className)
  5132. {
  5133. var constructorNodes = this.topLevelNodes();
  5134. for (var i = 0; i < constructorNodes.length; i++) {
  5135. var parent = constructorNodes[i];
  5136. if (parent._name === className) {
  5137. parent.revealNodeBySnapshotObjectId(parseInt(id, 10));
  5138. return;
  5139. }
  5140. }
  5141. }
  5142. this.snapshot.nodeClassName(parseInt(id, 10), didGetClassName.bind(this));
  5143. },
  5144.  
  5145. setDataSource: function(snapshotView, snapshot)
  5146. {
  5147. this.snapshotView = snapshotView;
  5148. this.snapshot = snapshot;
  5149. if (this._profileIndex === -1)
  5150. this._populateChildren();
  5151.  
  5152. if (this._objectIdToSelect) {
  5153. this.highlightObjectByHeapSnapshotId(this._objectIdToSelect);
  5154. this._objectIdToSelect = null;
  5155. }
  5156. },
  5157.  
  5158. _aggregatesReceived: function(key, aggregates)
  5159. {
  5160. for (var constructor in aggregates)
  5161. this.appendTopLevelNode(new WebInspector.HeapSnapshotConstructorNode(this, constructor, aggregates[constructor], key));
  5162. this.sortingChanged();
  5163. },
  5164.  
  5165. _populateChildren: function()
  5166. {
  5167.  
  5168. this.dispose();
  5169. this.removeTopLevelNodes();
  5170. this.resetSortingCache();
  5171.  
  5172. var key = this._profileIndex === -1 ? "allObjects" : this._minNodeId + ".." + this._maxNodeId;
  5173. var filter = this._profileIndex === -1 ? null : "function(node) { var id = node.id(); return id > " + this._minNodeId + " && id <= " + this._maxNodeId + "; }";
  5174.  
  5175. this.snapshot.aggregates(false, key, filter, this._aggregatesReceived.bind(this, key));
  5176. },
  5177.  
  5178. _filterSelectIndexChanged: function(profiles, profileIndex)
  5179. {
  5180. this._profileIndex = profileIndex;
  5181.  
  5182. delete this._maxNodeId;
  5183. delete this._minNodeId;
  5184.  
  5185. if (this._profileIndex !== -1) {
  5186. this._minNodeId = profileIndex > 0 ? profiles[profileIndex - 1].maxJSObjectId : 0;
  5187. this._maxNodeId = profiles[profileIndex].maxJSObjectId;
  5188. }
  5189.  
  5190. this._populateChildren();
  5191. },
  5192.  
  5193. __proto__: WebInspector.HeapSnapshotViewportDataGrid.prototype
  5194. }
  5195.  
  5196.  
  5197.  
  5198. WebInspector.HeapSnapshotDiffDataGrid = function()
  5199. {
  5200. var columns = {
  5201. object: { title: WebInspector.UIString("Constructor"), disclosure: true, sortable: true },
  5202. addedCount: { title: WebInspector.UIString("# New"), width: "72px", sortable: true },
  5203. removedCount: { title: WebInspector.UIString("# Deleted"), width: "72px", sortable: true },
  5204. countDelta: { title: "# Delta", width: "64px", sortable: true },
  5205. addedSize: { title: WebInspector.UIString("Alloc. Size"), width: "72px", sortable: true, sort: "descending" },
  5206. removedSize: { title: WebInspector.UIString("Freed Size"), width: "72px", sortable: true },
  5207. sizeDelta: { title: "Size Delta", width: "72px", sortable: true }
  5208. };
  5209. WebInspector.HeapSnapshotViewportDataGrid.call(this, columns);
  5210. }
  5211.  
  5212. WebInspector.HeapSnapshotDiffDataGrid.prototype = {
  5213.  
  5214. defaultPopulateCount: function()
  5215. {
  5216. return 50;
  5217. },
  5218.  
  5219. _sortFields: function(sortColumn, sortAscending)
  5220. {
  5221. return {
  5222. object: ["_name", sortAscending, "_count", false],
  5223. addedCount: ["_addedCount", sortAscending, "_name", true],
  5224. removedCount: ["_removedCount", sortAscending, "_name", true],
  5225. countDelta: ["_countDelta", sortAscending, "_name", true],
  5226. addedSize: ["_addedSize", sortAscending, "_name", true],
  5227. removedSize: ["_removedSize", sortAscending, "_name", true],
  5228. sizeDelta: ["_sizeDelta", sortAscending, "_name", true]
  5229. }[sortColumn];
  5230. },
  5231.  
  5232. setDataSource: function(snapshotView, snapshot)
  5233. {
  5234. this.snapshotView = snapshotView;
  5235. this.snapshot = snapshot;
  5236. },
  5237.  
  5238.  
  5239. setBaseDataSource: function(baseSnapshot)
  5240. {
  5241. this.baseSnapshot = baseSnapshot;
  5242. this.dispose();
  5243. this.removeTopLevelNodes();
  5244. this.resetSortingCache();
  5245. if (this.baseSnapshot === this.snapshot) {
  5246. this.dispatchEventToListeners("sorting complete");
  5247. return;
  5248. }
  5249. this._populateChildren();
  5250. },
  5251.  
  5252. _populateChildren: function()
  5253. {
  5254. function aggregatesForDiffReceived(aggregatesForDiff)
  5255. {
  5256. this.snapshot.calculateSnapshotDiff(this.baseSnapshot.uid, aggregatesForDiff, didCalculateSnapshotDiff.bind(this));
  5257. function didCalculateSnapshotDiff(diffByClassName)
  5258. {
  5259. for (var className in diffByClassName) {
  5260. var diff = diffByClassName[className];
  5261. this.appendTopLevelNode(new WebInspector.HeapSnapshotDiffNode(this, className, diff));
  5262. }
  5263. this.sortingChanged();
  5264. }
  5265. }
  5266.  
  5267.  
  5268.  
  5269. this.baseSnapshot.aggregatesForDiff(aggregatesForDiffReceived.bind(this));
  5270. },
  5271.  
  5272. __proto__: WebInspector.HeapSnapshotViewportDataGrid.prototype
  5273. }
  5274.  
  5275.  
  5276.  
  5277. WebInspector.HeapSnapshotDominatorsDataGrid = function()
  5278. {
  5279. var columns = {
  5280. object: { title: WebInspector.UIString("Object"), disclosure: true, sortable: true },
  5281. shallowSize: { title: WebInspector.UIString("Shallow Size"), width: "120px", sortable: true },
  5282. retainedSize: { title: WebInspector.UIString("Retained Size"), width: "120px", sort: "descending", sortable: true }
  5283. };
  5284. WebInspector.HeapSnapshotSortableDataGrid.call(this, columns);
  5285. this._objectIdToSelect = null;
  5286. }
  5287.  
  5288. WebInspector.HeapSnapshotDominatorsDataGrid.prototype = {
  5289.  
  5290. defaultPopulateCount: function()
  5291. {
  5292. return 25;
  5293. },
  5294.  
  5295. setDataSource: function(snapshotView, snapshot)
  5296. {
  5297. this.snapshotView = snapshotView;
  5298. this.snapshot = snapshot;
  5299.  
  5300. var fakeNode = { nodeIndex: this.snapshot.rootNodeIndex };
  5301. this.setRootNode(new WebInspector.HeapSnapshotDominatorObjectNode(this, fakeNode));
  5302. this.rootNode().sort();
  5303.  
  5304. if (this._objectIdToSelect) {
  5305. this.highlightObjectByHeapSnapshotId(this._objectIdToSelect);
  5306. this._objectIdToSelect = null;
  5307. }
  5308. },
  5309.  
  5310. sortingChanged: function()
  5311. {
  5312. this.rootNode().sort();
  5313. },
  5314.  
  5315.  
  5316. highlightObjectByHeapSnapshotId: function(id)
  5317. {
  5318. if (!this.snapshot) {
  5319. this._objectIdToSelect = id;
  5320. return;
  5321. }
  5322.  
  5323. function didGetDominators(dominatorIds)
  5324. {
  5325. if (!dominatorIds) {
  5326. WebInspector.log(WebInspector.UIString("Cannot find corresponding heap snapshot node"));
  5327. return;
  5328. }
  5329. var dominatorNode = this.rootNode();
  5330. expandNextDominator.call(this, dominatorIds, dominatorNode);
  5331. }
  5332.  
  5333. function expandNextDominator(dominatorIds, dominatorNode)
  5334. {
  5335. if (!dominatorNode) {
  5336. console.error("Cannot find dominator node");
  5337. return;
  5338. }
  5339. if (!dominatorIds.length) {
  5340. this.highlightNode(dominatorNode);
  5341. dominatorNode.element.scrollIntoViewIfNeeded(true);
  5342. return;
  5343. }
  5344. var snapshotObjectId = dominatorIds.pop();
  5345. dominatorNode.retrieveChildBySnapshotObjectId(snapshotObjectId, expandNextDominator.bind(this, dominatorIds));
  5346. }
  5347.  
  5348. this.snapshot.dominatorIdsForNode(parseInt(id, 10), didGetDominators.bind(this));
  5349. },
  5350.  
  5351. __proto__: WebInspector.HeapSnapshotSortableDataGrid.prototype
  5352. }
  5353.  
  5354. ;
  5355.  
  5356.  
  5357.  
  5358. WebInspector.HeapSnapshotGridNode = function(tree, hasChildren)
  5359. {
  5360. WebInspector.DataGridNode.call(this, null, hasChildren);
  5361. this._dataGrid = tree;
  5362. this._instanceCount = 0;
  5363.  
  5364. this._savedChildren = null;
  5365.  
  5366. this._retrievedChildrenRanges = [];
  5367. this.addEventListener("populate", this._populate, this);
  5368. }
  5369.  
  5370. WebInspector.HeapSnapshotGridNode.prototype = {
  5371.  
  5372. createProvider: function()
  5373. {
  5374. throw new Error("Needs implemented.");
  5375. },
  5376.  
  5377.  
  5378. _provider: function()
  5379. {
  5380. if (!this._providerObject)
  5381. this._providerObject = this.createProvider();
  5382. return this._providerObject;
  5383. },
  5384.  
  5385. createCell: function(columnIdentifier)
  5386. {
  5387. var cell = WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier);
  5388. if (this._searchMatched)
  5389. cell.addStyleClass("highlight");
  5390. return cell;
  5391. },
  5392.  
  5393. collapse: function()
  5394. {
  5395. WebInspector.DataGridNode.prototype.collapse.call(this);
  5396. this._dataGrid.updateVisibleNodes();
  5397. },
  5398.  
  5399. dispose: function()
  5400. {
  5401. if (this._provider())
  5402. this._provider().dispose();
  5403. for (var node = this.children[0]; node; node = node.traverseNextNode(true, this, true))
  5404. if (node.dispose)
  5405. node.dispose();
  5406. },
  5407.  
  5408. _reachableFromWindow: false,
  5409.  
  5410. queryObjectContent: function(callback)
  5411. {
  5412. },
  5413.  
  5414.  
  5415. wasDetached: function()
  5416. {
  5417. this._dataGrid.nodeWasDetached(this);
  5418. },
  5419.  
  5420. _toPercentString: function(num)
  5421. {
  5422. return num.toFixed(0) + "\u2009%"; 
  5423. },
  5424.  
  5425.  
  5426. childForPosition: function(nodePosition)
  5427. {
  5428. var indexOfFirsChildInRange = 0;
  5429. for (var i = 0; i < this._retrievedChildrenRanges.length; i++) {
  5430. var range = this._retrievedChildrenRanges[i];
  5431. if (range.from <= nodePosition && nodePosition < range.to) {
  5432. var childIndex = indexOfFirsChildInRange + nodePosition - range.from;
  5433. return this.children[childIndex];
  5434. }
  5435. indexOfFirsChildInRange += range.to - range.from + 1;
  5436. }
  5437. return null;
  5438. },
  5439.  
  5440. _createValueCell: function(columnIdentifier)
  5441. {
  5442. var cell = document.createElement("td");
  5443. cell.className = columnIdentifier + "-column";
  5444. if (this.dataGrid.snapshot.totalSize !== 0) {
  5445. var div = document.createElement("div");
  5446. var valueSpan = document.createElement("span");
  5447. valueSpan.textContent = this.data[columnIdentifier];
  5448. div.appendChild(valueSpan);
  5449. var percentColumn = columnIdentifier + "-percent";
  5450. if (percentColumn in this.data) {
  5451. var percentSpan = document.createElement("span");
  5452. percentSpan.className = "percent-column";
  5453. percentSpan.textContent = this.data[percentColumn];
  5454. div.appendChild(percentSpan);
  5455. }
  5456. cell.appendChild(div);
  5457. }
  5458. return cell;
  5459. },
  5460.  
  5461. _populate: function(event)
  5462. {
  5463. this.removeEventListener("populate", this._populate, this);
  5464. function sorted()
  5465. {
  5466. this._populateChildren();
  5467. }
  5468. this._provider().sortAndRewind(this.comparator(), sorted.bind(this));
  5469. },
  5470.  
  5471. expandWithoutPopulate: function(callback)
  5472. {
  5473.  
  5474. this.removeEventListener("populate", this._populate, this);
  5475. this.expand();
  5476. this._provider().sortAndRewind(this.comparator(), callback);
  5477. },
  5478.  
  5479.  
  5480. _populateChildren: function(fromPosition, toPosition, afterPopulate)
  5481. {
  5482. fromPosition = fromPosition || 0;
  5483. toPosition = toPosition || fromPosition + this._dataGrid.defaultPopulateCount();
  5484. var firstNotSerializedPosition = fromPosition;
  5485. function serializeNextChunk()
  5486. {
  5487. if (firstNotSerializedPosition >= toPosition)
  5488. return;
  5489. var end = Math.min(firstNotSerializedPosition + this._dataGrid.defaultPopulateCount(), toPosition);
  5490. this._provider().serializeItemsRange(firstNotSerializedPosition, end, childrenRetrieved.bind(this));
  5491. firstNotSerializedPosition = end;
  5492. }
  5493. function insertRetrievedChild(item, insertionIndex)
  5494. {
  5495. if (this._savedChildren) {
  5496. var hash = this._childHashForEntity(item);
  5497. if (hash in this._savedChildren) {
  5498. this.insertChild(this._savedChildren[hash], insertionIndex);
  5499. return;
  5500. }
  5501. }
  5502. this.insertChild(this._createChildNode(item), insertionIndex);
  5503. }
  5504. function insertShowMoreButton(from, to, insertionIndex)
  5505. {
  5506. var button = new WebInspector.ShowMoreDataGridNode(this._populateChildren.bind(this), from, to, this._dataGrid.defaultPopulateCount());
  5507. this.insertChild(button, insertionIndex);
  5508. }
  5509. function childrenRetrieved(items)
  5510. {
  5511. var itemIndex = 0;
  5512. var itemPosition = items.startPosition;
  5513. var insertionIndex = 0;
  5514.  
  5515. if (!this._retrievedChildrenRanges.length) {
  5516. if (items.startPosition > 0) {
  5517. this._retrievedChildrenRanges.push({from: 0, to: 0});
  5518. insertShowMoreButton.call(this, 0, items.startPosition, insertionIndex++);
  5519. }
  5520. this._retrievedChildrenRanges.push({from: items.startPosition, to: items.endPosition});
  5521. for (var i = 0, l = items.length; i < l; ++i)
  5522. insertRetrievedChild.call(this, items[i], insertionIndex++);
  5523. if (items.endPosition < items.totalLength)
  5524. insertShowMoreButton.call(this, items.endPosition, items.totalLength, insertionIndex++);
  5525. } else {
  5526. var rangeIndex = 0;
  5527. var found = false;
  5528. var range;
  5529. while (rangeIndex < this._retrievedChildrenRanges.length) {
  5530. range = this._retrievedChildrenRanges[rangeIndex];
  5531. if (range.to >= itemPosition) {
  5532. found = true;
  5533. break;
  5534. }
  5535. insertionIndex += range.to - range.from;
  5536.  
  5537. if (range.to < items.totalLength)
  5538. insertionIndex += 1;
  5539. ++rangeIndex;
  5540. }
  5541.  
  5542. if (!found || items.startPosition < range.from) {
  5543.  
  5544. this.children[insertionIndex - 1].setEndPosition(items.startPosition);
  5545. insertShowMoreButton.call(this, items.startPosition, found ? range.from : items.totalLength, insertionIndex);
  5546. range = {from: items.startPosition, to: items.startPosition};
  5547. if (!found)
  5548. rangeIndex = this._retrievedChildrenRanges.length;
  5549. this._retrievedChildrenRanges.splice(rangeIndex, 0, range);
  5550. } else {
  5551. insertionIndex += itemPosition - range.from;
  5552. }
  5553.  
  5554.  
  5555.  
  5556.  
  5557. while (range.to < items.endPosition) {
  5558.  
  5559. var skipCount = range.to - itemPosition;
  5560. insertionIndex += skipCount;
  5561. itemIndex += skipCount;
  5562. itemPosition = range.to;
  5563.  
  5564.  
  5565. var nextRange = this._retrievedChildrenRanges[rangeIndex + 1];
  5566. var newEndOfRange = nextRange ? nextRange.from : items.totalLength;
  5567. if (newEndOfRange > items.endPosition)
  5568. newEndOfRange = items.endPosition;
  5569. while (itemPosition < newEndOfRange) {
  5570. insertRetrievedChild.call(this, items[itemIndex++], insertionIndex++);
  5571. ++itemPosition;
  5572. }
  5573.  
  5574. if (nextRange && newEndOfRange === nextRange.from) {
  5575. range.to = nextRange.to;
  5576.  
  5577. this.removeChild(this.children[insertionIndex]);
  5578. this._retrievedChildrenRanges.splice(rangeIndex + 1, 1);
  5579. } else {
  5580. range.to = newEndOfRange;
  5581.  
  5582. if (newEndOfRange === items.totalLength)
  5583. this.removeChild(this.children[insertionIndex]);
  5584. else
  5585. this.children[insertionIndex].setStartPosition(items.endPosition);
  5586. }
  5587. }
  5588. }
  5589.  
  5590.  
  5591. this._instanceCount += items.length;
  5592. if (firstNotSerializedPosition < toPosition) {
  5593. serializeNextChunk.call(this);
  5594. return;
  5595. }
  5596.  
  5597. if (afterPopulate)
  5598. afterPopulate();
  5599. this.dispatchEventToListeners("populate complete");
  5600. }
  5601. serializeNextChunk.call(this);
  5602. },
  5603.  
  5604. _saveChildren: function()
  5605. {
  5606. this._savedChildren = null;
  5607. for (var i = 0, childrenCount = this.children.length; i < childrenCount; ++i) {
  5608. var child = this.children[i];
  5609. if (!child.expanded)
  5610. continue;
  5611. if (!this._savedChildren)
  5612. this._savedChildren = {};
  5613. this._savedChildren[this._childHashForNode(child)] = child;
  5614. }
  5615. },
  5616.  
  5617. sort: function()
  5618. {
  5619. this._dataGrid.recursiveSortingEnter();
  5620. function afterSort()
  5621. {
  5622. this._saveChildren();
  5623. this.removeChildren();
  5624. this._retrievedChildrenRanges = [];
  5625.  
  5626. function afterPopulate()
  5627. {
  5628. for (var i = 0, l = this.children.length; i < l; ++i) {
  5629. var child = this.children[i];
  5630. if (child.expanded)
  5631. child.sort();
  5632. }
  5633. this._dataGrid.recursiveSortingLeave();
  5634. }
  5635. var instanceCount = this._instanceCount;
  5636. this._instanceCount = 0;
  5637. this._populateChildren(0, instanceCount, afterPopulate.bind(this));
  5638. }
  5639.  
  5640. this._provider().sortAndRewind(this.comparator(), afterSort.bind(this));
  5641. },
  5642.  
  5643. __proto__: WebInspector.DataGridNode.prototype
  5644. }
  5645.  
  5646.  
  5647.  
  5648. WebInspector.HeapSnapshotGenericObjectNode = function(tree, node)
  5649. {
  5650. this.snapshotNodeIndex = 0;
  5651. WebInspector.HeapSnapshotGridNode.call(this, tree, false);
  5652.  
  5653. if (!node)
  5654. return;
  5655. this._name = node.name;
  5656. this._type = node.type;
  5657. this._distanceToWindow = node.distanceToWindow;
  5658. this._shallowSize = node.selfSize;
  5659. this._retainedSize = node.retainedSize;
  5660. this.snapshotNodeId = node.id;
  5661. this.snapshotNodeIndex = node.nodeIndex;
  5662. if (this._type === "string")
  5663. this._reachableFromWindow = true;
  5664. else if (this._type === "object" && this.isWindow(this._name)) {
  5665. this._name = this.shortenWindowURL(this._name, false);
  5666. this._reachableFromWindow = true;
  5667. } else if (node.flags & tree.snapshot.nodeFlags.canBeQueried)
  5668. this._reachableFromWindow = true;
  5669. if (node.flags & tree.snapshot.nodeFlags.detachedDOMTreeNode)
  5670. this.detachedDOMTreeNode = true;
  5671. };
  5672.  
  5673. WebInspector.HeapSnapshotGenericObjectNode.prototype = {
  5674. createCell: function(columnIdentifier)
  5675. {
  5676. var cell = columnIdentifier !== "object" ? this._createValueCell(columnIdentifier) : this._createObjectCell();
  5677. if (this._searchMatched)
  5678. cell.addStyleClass("highlight");
  5679. return cell;
  5680. },
  5681.  
  5682. _createObjectCell: function()
  5683. {
  5684. var cell = document.createElement("td");
  5685. cell.className = "object-column";
  5686. var div = document.createElement("div");
  5687. div.className = "source-code event-properties";
  5688. div.style.overflow = "visible";
  5689. var data = this.data["object"];
  5690. if (this._prefixObjectCell)
  5691. this._prefixObjectCell(div, data);
  5692. var valueSpan = document.createElement("span");
  5693. valueSpan.className = "value console-formatted-" + data.valueStyle;
  5694. valueSpan.textContent = data.value;
  5695. div.appendChild(valueSpan);
  5696. var idSpan = document.createElement("span");
  5697. idSpan.className = "console-formatted-id";
  5698. idSpan.textContent = " @" + data["nodeId"];
  5699. div.appendChild(idSpan);
  5700. if (this._postfixObjectCell)
  5701. this._postfixObjectCell(div, data);
  5702. cell.appendChild(div);
  5703. cell.addStyleClass("disclosure");
  5704. if (this.depth)
  5705. cell.style.setProperty("padding-left", (this.depth * this.dataGrid.indentWidth) + "px");
  5706. cell.heapSnapshotNode = this;
  5707. return cell;
  5708. },
  5709.  
  5710. get data()
  5711. {
  5712. var data = this._emptyData();
  5713.  
  5714. var value = this._name;
  5715. var valueStyle = "object";
  5716. switch (this._type) {
  5717. case "string":
  5718. value = "\"" + value + "\"";
  5719. valueStyle = "string";
  5720. break;
  5721. case "regexp":
  5722. value = "/" + value + "/";
  5723. valueStyle = "string";
  5724. break;
  5725. case "closure":
  5726. value = "function" + (value ? " " : "") + value + "()";
  5727. valueStyle = "function";
  5728. break;
  5729. case "number":
  5730. valueStyle = "number";
  5731. break;
  5732. case "hidden":
  5733. valueStyle = "null";
  5734. break;
  5735. case "array":
  5736. if (!value)
  5737. value = "[]";
  5738. else
  5739. value += "[]";
  5740. break;
  5741. };
  5742. if (this._reachableFromWindow)
  5743. valueStyle += " highlight";
  5744. if (value === "Object")
  5745. value = "";
  5746. if (this.detachedDOMTreeNode)
  5747. valueStyle += " detached-dom-tree-node";
  5748. data["object"] = { valueStyle: valueStyle, value: value, nodeId: this.snapshotNodeId };
  5749.  
  5750. var view = this.dataGrid.snapshotView;
  5751. data["distanceToWindow"] =  this._distanceToWindow;
  5752. data["shallowSize"] = Number.withThousandsSeparator(this._shallowSize);
  5753. data["retainedSize"] = Number.withThousandsSeparator(this._retainedSize);
  5754. data["shallowSize-percent"] = this._toPercentString(this._shallowSizePercent);
  5755. data["retainedSize-percent"] = this._toPercentString(this._retainedSizePercent);
  5756.  
  5757. return this._enhanceData ? this._enhanceData(data) : data;
  5758. },
  5759.  
  5760. queryObjectContent: function(callback, objectGroupName)
  5761. {
  5762. if (this._type === "string")
  5763. callback(WebInspector.RemoteObject.fromPrimitiveValue(this._name));
  5764. else {
  5765. function formatResult(error, object)
  5766. {
  5767. if (!error && object.type)
  5768. callback(WebInspector.RemoteObject.fromPayload(object), !!error);
  5769. else
  5770. callback(WebInspector.RemoteObject.fromPrimitiveValue(WebInspector.UIString("Not available")));
  5771. }
  5772. ProfilerAgent.getObjectByHeapObjectId(String(this.snapshotNodeId), objectGroupName, formatResult);
  5773. }
  5774. },
  5775.  
  5776. get _retainedSizePercent()
  5777. {
  5778. return this._retainedSize / this.dataGrid.snapshot.totalSize * 100.0;
  5779. },
  5780.  
  5781. get _shallowSizePercent()
  5782. {
  5783. return this._shallowSize / this.dataGrid.snapshot.totalSize * 100.0;
  5784. },
  5785.  
  5786. updateHasChildren: function()
  5787. {
  5788. function isEmptyCallback(isEmpty)
  5789. {
  5790. this.hasChildren = !isEmpty;
  5791. }
  5792. this._provider().isEmpty(isEmptyCallback.bind(this));
  5793. },
  5794.  
  5795. isWindow: function(fullName)
  5796. {
  5797. return fullName.substr(0, 9) === "Window";
  5798. },
  5799.  
  5800. shortenWindowURL: function(fullName, hasObjectId)
  5801. {
  5802. var startPos = fullName.indexOf("/");
  5803. var endPos = hasObjectId ? fullName.indexOf("@") : fullName.length;
  5804. if (startPos !== -1 && endPos !== -1) {
  5805. var fullURL = fullName.substring(startPos + 1, endPos).trimLeft();
  5806. var url = fullURL.trimURL();
  5807. if (url.length > 40)
  5808. url = url.trimMiddle(40);
  5809. return fullName.substr(0, startPos + 2) + url + fullName.substr(endPos);
  5810. } else
  5811. return fullName;
  5812. },
  5813.  
  5814. __proto__: WebInspector.HeapSnapshotGridNode.prototype
  5815. }
  5816.  
  5817.  
  5818. WebInspector.HeapSnapshotObjectNode = function(tree, isFromBaseSnapshot, edge, parentGridNode)
  5819. {
  5820. WebInspector.HeapSnapshotGenericObjectNode.call(this, tree, edge.node);
  5821. this._referenceName = edge.name;
  5822. this._referenceType = edge.type;
  5823. this._propertyAccessor = edge.propertyAccessor;
  5824. this._distanceToWindow = edge.distanceToWindow;
  5825. this.showRetainingEdges = tree.showRetainingEdges;
  5826. this._isFromBaseSnapshot = isFromBaseSnapshot;
  5827.  
  5828. this._parentGridNode = parentGridNode;
  5829. this._cycledWithAncestorGridNode = this._findAncestorWithSameSnapshotNodeId();
  5830. if (!this._cycledWithAncestorGridNode)
  5831. this.updateHasChildren();
  5832. }
  5833.  
  5834. WebInspector.HeapSnapshotObjectNode.prototype = {
  5835.  
  5836. createProvider: function()
  5837. {
  5838. var tree = this._dataGrid;
  5839. var showHiddenData = WebInspector.settings.showHeapSnapshotObjectsHiddenProperties.get();
  5840. var filter = "function(edge) {\n" +
  5841. "    return !edge.isInvisible()\n" +
  5842. "        && (" + !tree.showRetainingEdges + " || (edge.node().id() !== 1 && !edge.node().isSynthetic() && !edge.isWeak()))\n" +
  5843. "        && (" + showHiddenData + " || (!edge.isHidden() && !edge.node().isHidden()));\n" +
  5844. "}\n";
  5845. var snapshot = this._isFromBaseSnapshot ? tree.baseSnapshot : tree.snapshot;
  5846. if (this.showRetainingEdges)
  5847. return snapshot.createRetainingEdgesProvider(this.snapshotNodeIndex, filter);
  5848. else
  5849. return snapshot.createEdgesProvider(this.snapshotNodeIndex, filter);
  5850. },
  5851.  
  5852. _findAncestorWithSameSnapshotNodeId: function()
  5853. {
  5854. var ancestor = this._parentGridNode;
  5855. while (ancestor) {
  5856. if (ancestor.snapshotNodeId === this.snapshotNodeId)
  5857. return ancestor;
  5858. ancestor = ancestor._parentGridNode;
  5859. }
  5860. return null;
  5861. },
  5862.  
  5863. _createChildNode: function(item)
  5864. {
  5865. return new WebInspector.HeapSnapshotObjectNode(this._dataGrid, this._isFromBaseSnapshot, item, this);
  5866. },
  5867.  
  5868. _childHashForEntity: function(edge)
  5869. {
  5870. var prefix = this.showRetainingEdges ? edge.node.id + "#" : "";
  5871. return prefix + edge.type + "#" + edge.name;
  5872. },
  5873.  
  5874. _childHashForNode: function(childNode)
  5875. {
  5876. var prefix = this.showRetainingEdges ? childNode.snapshotNodeId + "#" : "";
  5877. return prefix + childNode._referenceType + "#" + childNode._referenceName;
  5878. },
  5879.  
  5880. comparator: function()
  5881. {
  5882. var sortAscending = this._dataGrid.sortOrder === "ascending";
  5883. var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier;
  5884. var sortFields = {
  5885. object: ["!edgeName", sortAscending, "retainedSize", false],
  5886. count: ["!edgeName", true, "retainedSize", false],
  5887. shallowSize: ["selfSize", sortAscending, "!edgeName", true],
  5888. retainedSize: ["retainedSize", sortAscending, "!edgeName", true],
  5889. distanceToWindow: ["distanceToWindow", sortAscending, "_name", true]
  5890. }[sortColumnIdentifier] || ["!edgeName", true, "retainedSize", false];
  5891. return WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator(sortFields);
  5892. },
  5893.  
  5894. _emptyData: function()
  5895. {
  5896. return { count: "", addedCount: "", removedCount: "", countDelta: "", addedSize: "", removedSize: "", sizeDelta: "" };
  5897. },
  5898.  
  5899. _enhanceData: function(data)
  5900. {
  5901. var name = this._referenceName;
  5902. if (name === "") name = "(empty)";
  5903. var nameClass = "name";
  5904. switch (this._referenceType) {
  5905. case "context":
  5906. nameClass = "console-formatted-number";
  5907. break;
  5908. case "internal":
  5909. case "hidden":
  5910. nameClass = "console-formatted-null";
  5911. break;
  5912. case "element":
  5913. name = "[" + name + "]";
  5914. break;
  5915. }
  5916. data["object"].nameClass = nameClass;
  5917. data["object"].name = name;
  5918. data["distanceToWindow"] = this._distanceToWindow;
  5919. return data;
  5920. },
  5921.  
  5922. _prefixObjectCell: function(div, data)
  5923. {
  5924. if (this._cycledWithAncestorGridNode)
  5925. div.className += " cycled-ancessor-node";
  5926.  
  5927. var nameSpan = document.createElement("span");
  5928. nameSpan.className = data.nameClass;
  5929. nameSpan.textContent = data.name;
  5930. div.appendChild(nameSpan);
  5931.  
  5932. var separatorSpan = document.createElement("span");
  5933. separatorSpan.className = "grayed";
  5934. separatorSpan.textContent = this.showRetainingEdges ? " in " : " :: ";
  5935. div.appendChild(separatorSpan);
  5936. },
  5937.  
  5938. __proto__: WebInspector.HeapSnapshotGenericObjectNode.prototype
  5939. }
  5940.  
  5941.  
  5942. WebInspector.HeapSnapshotInstanceNode = function(tree, baseSnapshot, snapshot, node)
  5943. {
  5944. WebInspector.HeapSnapshotGenericObjectNode.call(this, tree, node);
  5945. this._baseSnapshotOrSnapshot = baseSnapshot || snapshot;
  5946. this._isDeletedNode = !!baseSnapshot;
  5947. this.updateHasChildren();
  5948. };
  5949.  
  5950. WebInspector.HeapSnapshotInstanceNode.prototype = {
  5951. createProvider: function()
  5952. {
  5953. var showHiddenData = WebInspector.settings.showHeapSnapshotObjectsHiddenProperties.get();
  5954. return this._baseSnapshotOrSnapshot.createEdgesProvider(
  5955. this.snapshotNodeIndex,
  5956. "function(edge) {" +
  5957. "    return !edge.isInvisible()" +
  5958. "        && (" + showHiddenData + " || (!edge.isHidden() && !edge.node().isHidden()));" +
  5959. "}");
  5960. },
  5961.  
  5962. _createChildNode: function(item)
  5963. {
  5964. return new WebInspector.HeapSnapshotObjectNode(this._dataGrid, this._isDeletedNode, item, null);
  5965. },
  5966.  
  5967. _childHashForEntity: function(edge)
  5968. {
  5969. return edge.type + "#" + edge.name;
  5970. },
  5971.  
  5972. _childHashForNode: function(childNode)
  5973. {
  5974. return childNode._referenceType + "#" + childNode._referenceName;
  5975. },
  5976.  
  5977. comparator: function()
  5978. {
  5979. var sortAscending = this._dataGrid.sortOrder === "ascending";
  5980. var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier;
  5981. var sortFields = {
  5982. object: ["!edgeName", sortAscending, "retainedSize", false],
  5983. distanceToWindow: ["distanceToWindow", sortAscending, "retainedSize", false],
  5984. count: ["!edgeName", true, "retainedSize", false],
  5985. addedSize: ["selfSize", sortAscending, "!edgeName", true],
  5986. removedSize: ["selfSize", sortAscending, "!edgeName", true],
  5987. shallowSize: ["selfSize", sortAscending, "!edgeName", true],
  5988. retainedSize: ["retainedSize", sortAscending, "!edgeName", true]
  5989. }[sortColumnIdentifier] || ["!edgeName", true, "retainedSize", false];
  5990. return WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator(sortFields);
  5991. },
  5992.  
  5993. _emptyData: function()
  5994. {
  5995. return {count:"", countDelta:"", sizeDelta: ""};
  5996. },
  5997.  
  5998. _enhanceData: function(data)
  5999. {
  6000. if (this._isDeletedNode) {
  6001. data["addedCount"] = "";
  6002. data["addedSize"] = "";
  6003. data["removedCount"] = "\u2022";
  6004. data["removedSize"] = Number.withThousandsSeparator(this._shallowSize);
  6005. } else {
  6006. data["addedCount"] = "\u2022";
  6007. data["addedSize"] = Number.withThousandsSeparator(this._shallowSize);
  6008. data["removedCount"] = "";
  6009. data["removedSize"] = "";
  6010. }
  6011. return data;
  6012. },
  6013.  
  6014. get isDeletedNode()
  6015. {
  6016. return this._isDeletedNode;
  6017. },
  6018.  
  6019. __proto__: WebInspector.HeapSnapshotGenericObjectNode.prototype
  6020. }
  6021.  
  6022.  
  6023. WebInspector.HeapSnapshotConstructorNode = function(tree, className, aggregate, aggregatesKey)
  6024. {
  6025. WebInspector.HeapSnapshotGridNode.call(this, tree, aggregate.count > 0);
  6026. this._name = className;
  6027. this._aggregatesKey = aggregatesKey;
  6028. this._distanceToWindow = aggregate.distanceToWindow;
  6029. this._count = aggregate.count;
  6030. this._shallowSize = aggregate.self;
  6031. this._retainedSize = aggregate.maxRet;
  6032. }
  6033.  
  6034. WebInspector.HeapSnapshotConstructorNode.prototype = {
  6035.  
  6036. createProvider: function()
  6037. {
  6038. return this._dataGrid.snapshot.createNodesProviderForClass(this._name, this._aggregatesKey)
  6039. },
  6040.  
  6041.  
  6042. revealNodeBySnapshotObjectId: function(snapshotObjectId)
  6043. {
  6044. function didExpand()
  6045. {
  6046. this._provider().nodePosition(snapshotObjectId, didGetNodePosition.bind(this));
  6047. }
  6048.  
  6049. function didGetNodePosition(nodePosition)
  6050. {
  6051. if (nodePosition === -1)
  6052. this.collapse();
  6053. else
  6054. this._populateChildren(nodePosition, null, didPopulateChildren.bind(this, nodePosition));
  6055. }
  6056.  
  6057. function didPopulateChildren(nodePosition)
  6058. {
  6059. var indexOfFirsChildInRange = 0;
  6060. for (var i = 0; i < this._retrievedChildrenRanges.length; i++) {
  6061. var range = this._retrievedChildrenRanges[i];
  6062. if (range.from <= nodePosition && nodePosition < range.to) {
  6063. var childIndex = indexOfFirsChildInRange + nodePosition - range.from;
  6064. var instanceNode = this.children[childIndex];
  6065. this._dataGrid.highlightNode(instanceNode);
  6066. return;
  6067. }
  6068. indexOfFirsChildInRange += range.to - range.from + 1;
  6069. }
  6070. }
  6071.  
  6072. this.expandWithoutPopulate(didExpand.bind(this));
  6073. },
  6074.  
  6075. createCell: function(columnIdentifier)
  6076. {
  6077. var cell = columnIdentifier !== "object" ? this._createValueCell(columnIdentifier) : WebInspector.HeapSnapshotGridNode.prototype.createCell.call(this, columnIdentifier);
  6078. if (this._searchMatched)
  6079. cell.addStyleClass("highlight");
  6080. return cell;
  6081. },
  6082.  
  6083. _createChildNode: function(item)
  6084. {
  6085. return new WebInspector.HeapSnapshotInstanceNode(this._dataGrid, null, this._dataGrid.snapshot, item);
  6086. },
  6087.  
  6088. comparator: function()
  6089. {
  6090. var sortAscending = this._dataGrid.sortOrder === "ascending";
  6091. var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier;
  6092. var sortFields = {
  6093. object: ["id", sortAscending, "retainedSize", false],
  6094. distanceToWindow: ["distanceToWindow", true, "retainedSize", false],
  6095. count: ["id", true, "retainedSize", false],
  6096. shallowSize: ["selfSize", sortAscending, "id", true],
  6097. retainedSize: ["retainedSize", sortAscending, "id", true]
  6098. }[sortColumnIdentifier];
  6099. return WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator(sortFields);
  6100. },
  6101.  
  6102. _childHashForEntity: function(node)
  6103. {
  6104. return node.id;
  6105. },
  6106.  
  6107. _childHashForNode: function(childNode)
  6108. {
  6109. return childNode.snapshotNodeId;
  6110. },
  6111.  
  6112. get data()
  6113. {
  6114. var data = { object: this._name };
  6115. var view = this.dataGrid.snapshotView;
  6116. data["count"] =  Number.withThousandsSeparator(this._count);
  6117. data["distanceToWindow"] =  this._distanceToWindow;
  6118. data["shallowSize"] = Number.withThousandsSeparator(this._shallowSize);
  6119. data["retainedSize"] = Number.withThousandsSeparator(this._retainedSize);
  6120. data["count-percent"] =  this._toPercentString(this._countPercent);
  6121. data["shallowSize-percent"] = this._toPercentString(this._shallowSizePercent);
  6122. data["retainedSize-percent"] = this._toPercentString(this._retainedSizePercent);
  6123. return data;
  6124. },
  6125.  
  6126. get _countPercent()
  6127. {
  6128. return this._count / this.dataGrid.snapshot.nodeCount * 100.0;
  6129. },
  6130.  
  6131. get _retainedSizePercent()
  6132. {
  6133. return this._retainedSize / this.dataGrid.snapshot.totalSize * 100.0;
  6134. },
  6135.  
  6136. get _shallowSizePercent()
  6137. {
  6138. return this._shallowSize / this.dataGrid.snapshot.totalSize * 100.0;
  6139. },
  6140.  
  6141. __proto__: WebInspector.HeapSnapshotGridNode.prototype
  6142. }
  6143.  
  6144.  
  6145.  
  6146. WebInspector.HeapSnapshotDiffNodesProvider = function(addedNodesProvider, deletedNodesProvider, addedCount, removedCount)
  6147. {
  6148. this._addedNodesProvider = addedNodesProvider;
  6149. this._deletedNodesProvider = deletedNodesProvider;
  6150. this._addedCount = addedCount;
  6151. this._removedCount = removedCount;
  6152. }
  6153.  
  6154. WebInspector.HeapSnapshotDiffNodesProvider.prototype = {
  6155. dispose: function()
  6156. {
  6157. this._addedNodesProvider.dispose();
  6158. this._deletedNodesProvider.dispose();
  6159. },
  6160.  
  6161. isEmpty: function(callback)
  6162. {
  6163. callback(false);
  6164. },
  6165.  
  6166. serializeItemsRange: function(beginPosition, endPosition, callback)
  6167. {
  6168. function didReceiveAllItems(items)
  6169. {
  6170. items.totalLength = this._addedCount + this._removedCount;
  6171. callback(items);
  6172. }
  6173.  
  6174. function didReceiveDeletedItems(addedItems, items)
  6175. {
  6176. if (!addedItems.length)
  6177. addedItems.startPosition = this._addedCount + items.startPosition;
  6178. for (var i = 0; i < items.length; i++) {
  6179. items[i].isAddedNotRemoved = false;
  6180. addedItems.push(items[i]);
  6181. }
  6182. addedItems.endPosition = this._addedCount + items.endPosition;
  6183. didReceiveAllItems.call(this, addedItems);
  6184. }
  6185.  
  6186. function didReceiveAddedItems(items)
  6187. {
  6188. for (var i = 0; i < items.length; i++)
  6189. items[i].isAddedNotRemoved = true;
  6190. if (items.endPosition < endPosition)
  6191. return this._deletedNodesProvider.serializeItemsRange(0, endPosition - items.endPosition, didReceiveDeletedItems.bind(this, items));
  6192.  
  6193. items.totalLength = this._addedCount + this._removedCount;
  6194. didReceiveAllItems.call(this, items);
  6195. }
  6196.  
  6197. if (beginPosition < this._addedCount)
  6198. this._addedNodesProvider.serializeItemsRange(beginPosition, endPosition, didReceiveAddedItems.bind(this));
  6199. else
  6200. this._deletedNodesProvider.serializeItemsRange(beginPosition - this._addedCount, endPosition - this._addedCount, didReceiveDeletedItems.bind(this, []));
  6201. },
  6202.  
  6203. sortAndRewind: function(comparator, callback)
  6204. {
  6205. function afterSort()
  6206. {
  6207. this._deletedNodesProvider.sortAndRewind(comparator, callback);
  6208. }
  6209. this._addedNodesProvider.sortAndRewind(comparator, afterSort.bind(this));
  6210. }
  6211. };
  6212.  
  6213.  
  6214. WebInspector.HeapSnapshotDiffNode = function(tree, className, diffForClass)
  6215. {
  6216. WebInspector.HeapSnapshotGridNode.call(this, tree, true);
  6217. this._name = className;
  6218.  
  6219. this._addedCount = diffForClass.addedCount;
  6220. this._removedCount = diffForClass.removedCount;
  6221. this._countDelta = diffForClass.countDelta;
  6222. this._addedSize = diffForClass.addedSize;
  6223. this._removedSize = diffForClass.removedSize;
  6224. this._sizeDelta = diffForClass.sizeDelta;
  6225. this._deletedIndexes = diffForClass.deletedIndexes;
  6226. }
  6227.  
  6228. WebInspector.HeapSnapshotDiffNode.prototype = {
  6229.  
  6230. createProvider: function()
  6231. {
  6232. var tree = this._dataGrid;
  6233. return  new WebInspector.HeapSnapshotDiffNodesProvider(
  6234. tree.snapshot.createAddedNodesProvider(tree.baseSnapshot.uid, this._name),
  6235. tree.baseSnapshot.createDeletedNodesProvider(this._deletedIndexes),
  6236. this._addedCount,
  6237. this._removedCount);
  6238. },
  6239.  
  6240. _createChildNode: function(item)
  6241. {
  6242. if (item.isAddedNotRemoved)
  6243. return new WebInspector.HeapSnapshotInstanceNode(this._dataGrid, null, this._dataGrid.snapshot, item);
  6244. else
  6245. return new WebInspector.HeapSnapshotInstanceNode(this._dataGrid, this._dataGrid.baseSnapshot, null, item);
  6246. },
  6247.  
  6248. _childHashForEntity: function(node)
  6249. {
  6250. return node.id;
  6251. },
  6252.  
  6253. _childHashForNode: function(childNode)
  6254. {
  6255. return childNode.snapshotNodeId;
  6256. },
  6257.  
  6258. comparator: function()
  6259. {
  6260. var sortAscending = this._dataGrid.sortOrder === "ascending";
  6261. var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier;
  6262. var sortFields = {
  6263. object: ["id", sortAscending, "selfSize", false],
  6264. addedCount: ["selfSize", sortAscending, "id", true],
  6265. removedCount: ["selfSize", sortAscending, "id", true],
  6266. countDelta: ["selfSize", sortAscending, "id", true],
  6267. addedSize: ["selfSize", sortAscending, "id", true],
  6268. removedSize: ["selfSize", sortAscending, "id", true],
  6269. sizeDelta: ["selfSize", sortAscending, "id", true]
  6270. }[sortColumnIdentifier];
  6271. return WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator(sortFields);
  6272. },
  6273.  
  6274. _signForDelta: function(delta)
  6275. {
  6276. if (delta === 0)
  6277. return "";
  6278. if (delta > 0)
  6279. return "+";
  6280. else
  6281. return "\u2212";  
  6282. },
  6283.  
  6284. get data()
  6285. {
  6286. var data = {object: this._name};
  6287.  
  6288. data["addedCount"] = Number.withThousandsSeparator(this._addedCount);
  6289. data["removedCount"] = Number.withThousandsSeparator(this._removedCount);
  6290. data["countDelta"] = this._signForDelta(this._countDelta) + Number.withThousandsSeparator(Math.abs(this._countDelta));
  6291. data["addedSize"] = Number.withThousandsSeparator(this._addedSize);
  6292. data["removedSize"] = Number.withThousandsSeparator(this._removedSize);
  6293. data["sizeDelta"] = this._signForDelta(this._sizeDelta) + Number.withThousandsSeparator(Math.abs(this._sizeDelta));
  6294.  
  6295. return data;
  6296. },
  6297.  
  6298. __proto__: WebInspector.HeapSnapshotGridNode.prototype
  6299. }
  6300.  
  6301.  
  6302.  
  6303. WebInspector.HeapSnapshotDominatorObjectNode = function(tree, node)
  6304. {
  6305. WebInspector.HeapSnapshotGenericObjectNode.call(this, tree, node);
  6306. this.updateHasChildren();
  6307. };
  6308.  
  6309. WebInspector.HeapSnapshotDominatorObjectNode.prototype = {
  6310.  
  6311. createProvider: function()
  6312. {
  6313. return this._dataGrid.snapshot.createNodesProviderForDominator(this.snapshotNodeIndex);
  6314. },
  6315.  
  6316.  
  6317. retrieveChildBySnapshotObjectId: function(snapshotObjectId, callback)
  6318. {
  6319. function didExpand()
  6320. {
  6321. this._provider().nodePosition(snapshotObjectId, didGetNodePosition.bind(this));
  6322. }
  6323.  
  6324. function didGetNodePosition(nodePosition)
  6325. {
  6326. if (nodePosition === -1) {
  6327. this.collapse();
  6328. callback(null);
  6329. } else
  6330. this._populateChildren(nodePosition, null, didPopulateChildren.bind(this, nodePosition));
  6331. }
  6332.  
  6333. function didPopulateChildren(nodePosition)
  6334. {
  6335. var child = this.childForPosition(nodePosition);
  6336. callback(child);
  6337. }
  6338.  
  6339.  
  6340.  
  6341. this.hasChildren = true;
  6342. this.expandWithoutPopulate(didExpand.bind(this));
  6343. },
  6344.  
  6345. _createChildNode: function(item)
  6346. {
  6347. return new WebInspector.HeapSnapshotDominatorObjectNode(this._dataGrid, item);
  6348. },
  6349.  
  6350. _childHashForEntity: function(node)
  6351. {
  6352. return node.id;
  6353. },
  6354.  
  6355. _childHashForNode: function(childNode)
  6356. {
  6357. return childNode.snapshotNodeId;
  6358. },
  6359.  
  6360. comparator: function()
  6361. {
  6362. var sortAscending = this._dataGrid.sortOrder === "ascending";
  6363. var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier;
  6364. var sortFields = {
  6365. object: ["id", sortAscending, "retainedSize", false],
  6366. shallowSize: ["selfSize", sortAscending, "id", true],
  6367. retainedSize: ["retainedSize", sortAscending, "id", true]
  6368. }[sortColumnIdentifier];
  6369. return WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator(sortFields);
  6370. },
  6371.  
  6372. _emptyData: function()
  6373. {
  6374. return {};
  6375. },
  6376.  
  6377. __proto__: WebInspector.HeapSnapshotGenericObjectNode.prototype
  6378. }
  6379.  
  6380. ;
  6381.  
  6382.  
  6383.  
  6384. WebInspector.HeapSnapshotLoader = function()
  6385. {
  6386. this._reset();
  6387. }
  6388.  
  6389. WebInspector.HeapSnapshotLoader.prototype = {
  6390. dispose: function()
  6391. {
  6392. this._reset();
  6393. },
  6394.  
  6395. _reset: function()
  6396. {
  6397. this._json = "";
  6398. this._state = "find-snapshot-info";
  6399. this._snapshot = {};
  6400. },
  6401.  
  6402. close: function()
  6403. {
  6404. if (this._json)
  6405. this._parseStringsArray();
  6406. },
  6407.  
  6408. buildSnapshot: function()
  6409. {
  6410. var result = new WebInspector.HeapSnapshot(this._snapshot);
  6411. this._reset();
  6412. return result;
  6413. },
  6414.  
  6415. _parseUintArray: function()
  6416. {
  6417. var index = 0;
  6418. var char0 = "0".charCodeAt(0), char9 = "9".charCodeAt(0), closingBracket = "]".charCodeAt(0);
  6419. var length = this._json.length;
  6420. while (true) {
  6421. while (index < length) {
  6422. var code = this._json.charCodeAt(index);
  6423. if (char0 <= code && code <= char9)
  6424. break;
  6425. else if (code === closingBracket) {
  6426. this._json = this._json.slice(index + 1);
  6427. return false;
  6428. }
  6429. ++index;
  6430. }
  6431. if (index === length) {
  6432. this._json = "";
  6433. return true;
  6434. }
  6435. var nextNumber = 0;
  6436. var startIndex = index;
  6437. while (index < length) {
  6438. var code = this._json.charCodeAt(index);
  6439. if (char0 > code || code > char9)
  6440. break;
  6441. nextNumber *= 10;
  6442. nextNumber += (code - char0);
  6443. ++index;
  6444. }
  6445. if (index === length) {
  6446. this._json = this._json.slice(startIndex);
  6447. return true;
  6448. }
  6449. this._array[this._arrayIndex++] = nextNumber;
  6450. }
  6451. },
  6452.  
  6453. _parseStringsArray: function()
  6454. {
  6455. var closingBracketIndex = this._json.lastIndexOf("]");
  6456. if (closingBracketIndex === -1)
  6457. throw new Error("Incomplete JSON");
  6458. this._json = this._json.slice(0, closingBracketIndex + 1);
  6459. this._snapshot.strings = JSON.parse(this._json);
  6460. },
  6461.  
  6462.  
  6463. write: function(chunk)
  6464. {
  6465. this._json += chunk;
  6466. switch (this._state) {
  6467. case "find-snapshot-info": {
  6468. var snapshotToken = "\"snapshot\"";
  6469. var snapshotTokenIndex = this._json.indexOf(snapshotToken);
  6470. if (snapshotTokenIndex === -1)
  6471. throw new Error("Snapshot token not found");
  6472. this._json = this._json.slice(snapshotTokenIndex + snapshotToken.length + 1);
  6473. this._state = "parse-snapshot-info";
  6474. }
  6475. case "parse-snapshot-info": {
  6476. var closingBracketIndex = WebInspector.findBalancedCurlyBrackets(this._json);
  6477. if (closingBracketIndex === -1)
  6478. return;
  6479. this._snapshot.snapshot =   (JSON.parse(this._json.slice(0, closingBracketIndex)));
  6480. this._json = this._json.slice(closingBracketIndex);
  6481. this._state = "find-nodes";
  6482. }
  6483. case "find-nodes": {
  6484. var nodesToken = "\"nodes\"";
  6485. var nodesTokenIndex = this._json.indexOf(nodesToken);
  6486. if (nodesTokenIndex === -1)
  6487. return;
  6488. var bracketIndex = this._json.indexOf("[", nodesTokenIndex);
  6489. if (bracketIndex === -1)
  6490. return;
  6491. this._json = this._json.slice(bracketIndex + 1);
  6492. var node_fields_count = this._snapshot.snapshot.meta.node_fields.length;
  6493. var nodes_length = this._snapshot.snapshot.node_count * node_fields_count;
  6494. this._array = new Uint32Array(nodes_length);
  6495. this._arrayIndex = 0;
  6496. this._state = "parse-nodes";
  6497. }
  6498. case "parse-nodes": {
  6499. if (this._parseUintArray())
  6500. return;
  6501. this._snapshot.nodes = this._array;
  6502. this._state = "find-edges";
  6503. this._array = null;
  6504. }
  6505. case "find-edges": {
  6506. var edgesToken = "\"edges\"";
  6507. var edgesTokenIndex = this._json.indexOf(edgesToken);
  6508. if (edgesTokenIndex === -1)
  6509. return;
  6510. var bracketIndex = this._json.indexOf("[", edgesTokenIndex);
  6511. if (bracketIndex === -1)
  6512. return;
  6513. this._json = this._json.slice(bracketIndex + 1);
  6514. var edge_fields_count = this._snapshot.snapshot.meta.edge_fields.length;
  6515. var edges_length = this._snapshot.snapshot.edge_count * edge_fields_count;
  6516. this._array = new Uint32Array(edges_length);
  6517. this._arrayIndex = 0;
  6518. this._state = "parse-edges";
  6519. }
  6520. case "parse-edges": {
  6521. if (this._parseUintArray())
  6522. return;
  6523. this._snapshot.edges = this._array;
  6524. this._array = null;
  6525. this._state = "find-strings";
  6526. }
  6527. case "find-strings": {
  6528. var stringsToken = "\"strings\"";
  6529. var stringsTokenIndex = this._json.indexOf(stringsToken);
  6530. if (stringsTokenIndex === -1)
  6531. return;
  6532. var bracketIndex = this._json.indexOf("[", stringsTokenIndex);
  6533. if (bracketIndex === -1)
  6534. return;
  6535. this._json = this._json.slice(bracketIndex);
  6536. this._state = "accumulate-strings";
  6537. break;
  6538. }
  6539. case "accumulate-strings":
  6540. break;
  6541. }
  6542. }
  6543. };
  6544. ;
  6545.  
  6546.  
  6547.  
  6548. WebInspector.HeapSnapshotWorkerWrapper = function()
  6549. {
  6550. }
  6551.  
  6552. WebInspector.HeapSnapshotWorkerWrapper.prototype =  {
  6553. postMessage: function(message)
  6554. {
  6555. },
  6556. terminate: function()
  6557. {
  6558. },
  6559.  
  6560. __proto__: WebInspector.Object.prototype
  6561. }
  6562.  
  6563.  
  6564. WebInspector.HeapSnapshotRealWorker = function()
  6565. {
  6566. this._worker = new Worker("HeapSnapshotWorker.js");
  6567. this._worker.addEventListener("message", this._messageReceived.bind(this), false);
  6568. }
  6569.  
  6570. WebInspector.HeapSnapshotRealWorker.prototype = {
  6571. _messageReceived: function(event)
  6572. {
  6573. var message = event.data;
  6574. if ("callId" in message)
  6575. this.dispatchEventToListeners("message", message);
  6576. else {
  6577. if (message.object !== "console") {
  6578. console.log(WebInspector.UIString("Worker asks to call a method '%s' on an unsupported object '%s'.", message.method, message.object));
  6579. return;
  6580. }
  6581. if (message.method !== "log" && message.method !== "info" && message.method !== "error") {
  6582. console.log(WebInspector.UIString("Worker asks to call an unsupported method '%s' on the console object.", message.method));
  6583. return;
  6584. }
  6585. console[message.method].apply(window[message.object], message.arguments);
  6586. }
  6587. },
  6588.  
  6589. postMessage: function(message)
  6590. {
  6591. this._worker.postMessage(message);
  6592. },
  6593.  
  6594. terminate: function()
  6595. {
  6596. this._worker.terminate();
  6597. },
  6598.  
  6599. __proto__: WebInspector.HeapSnapshotWorkerWrapper.prototype
  6600. }
  6601.  
  6602.  
  6603.  
  6604. WebInspector.AsyncTaskQueue = function()
  6605. {
  6606. this._queue = [];
  6607. this._isTimerSheduled = false;
  6608. }
  6609.  
  6610. WebInspector.AsyncTaskQueue.prototype = {
  6611.  
  6612. addTask: function(task)
  6613. {
  6614. this._queue.push(task);
  6615. this._scheduleTimer();
  6616. },
  6617.  
  6618. _onTimeout: function()
  6619. {
  6620. this._isTimerSheduled = false;
  6621. var queue = this._queue;
  6622. this._queue = [];
  6623. for (var i = 0; i < queue.length; i++) {
  6624. try {
  6625. queue[i]();
  6626. } catch (e) {
  6627. console.error("Exception while running task: " + e.stack);
  6628. }
  6629. }
  6630. this._scheduleTimer();
  6631. },
  6632.  
  6633. _scheduleTimer: function()
  6634. {
  6635. if (this._queue.length && !this._isTimerSheduled) {
  6636. setTimeout(this._onTimeout.bind(this), 0);
  6637. this._isTimerSheduled = true;
  6638. }
  6639. }
  6640. }
  6641.  
  6642.  
  6643. WebInspector.HeapSnapshotFakeWorker = function()
  6644. {
  6645. this._dispatcher = new WebInspector.HeapSnapshotWorkerDispatcher(window, this._postMessageFromWorker.bind(this));
  6646. this._asyncTaskQueue = new WebInspector.AsyncTaskQueue();
  6647. }
  6648.  
  6649. WebInspector.HeapSnapshotFakeWorker.prototype = {
  6650. postMessage: function(message)
  6651. {
  6652. function dispatch()
  6653. {
  6654. if (this._dispatcher)
  6655. this._dispatcher.dispatchMessage({data: message});
  6656. }
  6657. this._asyncTaskQueue.addTask(dispatch.bind(this));
  6658. },
  6659.  
  6660. terminate: function()
  6661. {
  6662. this._dispatcher = null;
  6663. },
  6664.  
  6665. _postMessageFromWorker: function(message)
  6666. {
  6667. function send()
  6668. {
  6669. this.dispatchEventToListeners("message", message);
  6670. }
  6671. this._asyncTaskQueue.addTask(send.bind(this));
  6672. },
  6673.  
  6674. __proto__: WebInspector.HeapSnapshotWorkerWrapper.prototype
  6675. }
  6676.  
  6677.  
  6678.  
  6679. WebInspector.HeapSnapshotWorker = function()
  6680. {
  6681. this._nextObjectId = 1;
  6682. this._nextCallId = 1;
  6683. this._callbacks = [];
  6684. this._previousCallbacks = [];
  6685.  
  6686. this._worker = typeof InspectorTest === "undefined" ? new WebInspector.HeapSnapshotRealWorker() : new WebInspector.HeapSnapshotFakeWorker();
  6687. this._worker.addEventListener("message", this._messageReceived, this);
  6688. }
  6689.  
  6690. WebInspector.HeapSnapshotWorker.prototype = {
  6691. createObject: function(constructorName)
  6692. {
  6693. var proxyConstructorFunction = this._findFunction(constructorName + "Proxy");
  6694. var objectId = this._nextObjectId++;
  6695. var proxy = new proxyConstructorFunction(this, objectId);
  6696. this._postMessage({callId: this._nextCallId++, disposition: "create", objectId: objectId, methodName: constructorName});
  6697. return proxy;
  6698. },
  6699.  
  6700. dispose: function()
  6701. {
  6702. this._worker.terminate();
  6703. if (this._interval)
  6704. clearInterval(this._interval);
  6705. },
  6706.  
  6707. disposeObject: function(objectId)
  6708. {
  6709. this._postMessage({callId: this._nextCallId++, disposition: "dispose", objectId: objectId});
  6710. },
  6711.  
  6712. callGetter: function(callback, objectId, getterName)
  6713. {
  6714. var callId = this._nextCallId++;
  6715. this._callbacks[callId] = callback;
  6716. this._postMessage({callId: callId, disposition: "getter", objectId: objectId, methodName: getterName});
  6717. },
  6718.  
  6719. callFactoryMethod: function(callback, objectId, methodName, proxyConstructorName)
  6720. {
  6721. var callId = this._nextCallId++;
  6722. var methodArguments = Array.prototype.slice.call(arguments, 4);
  6723. var newObjectId = this._nextObjectId++;
  6724. var proxyConstructorFunction = this._findFunction(proxyConstructorName);
  6725. if (callback) {
  6726. function wrapCallback(remoteResult)
  6727. {
  6728. callback(remoteResult ? new proxyConstructorFunction(this, newObjectId) : null);
  6729. }
  6730. this._callbacks[callId] = wrapCallback.bind(this);
  6731. this._postMessage({callId: callId, disposition: "factory", objectId: objectId, methodName: methodName, methodArguments: methodArguments, newObjectId: newObjectId});
  6732. return null;
  6733. } else {
  6734. this._postMessage({callId: callId, disposition: "factory", objectId: objectId, methodName: methodName, methodArguments: methodArguments, newObjectId: newObjectId});
  6735. return new proxyConstructorFunction(this, newObjectId);
  6736. }
  6737. },
  6738.  
  6739. callMethod: function(callback, objectId, methodName)
  6740. {
  6741. var callId = this._nextCallId++;
  6742. var methodArguments = Array.prototype.slice.call(arguments, 3);
  6743. if (callback)
  6744. this._callbacks[callId] = callback;
  6745. this._postMessage({callId: callId, disposition: "method", objectId: objectId, methodName: methodName, methodArguments: methodArguments});
  6746. },
  6747.  
  6748. startCheckingForLongRunningCalls: function()
  6749. {
  6750. if (this._interval)
  6751. return;
  6752. this._checkLongRunningCalls();
  6753. this._interval = setInterval(this._checkLongRunningCalls.bind(this), 300);
  6754. },
  6755.  
  6756. _checkLongRunningCalls: function()
  6757. {
  6758. for (var callId in this._previousCallbacks)
  6759. if (!(callId in this._callbacks))
  6760. delete this._previousCallbacks[callId];
  6761. var hasLongRunningCalls = false;
  6762. for (callId in this._previousCallbacks) {
  6763. hasLongRunningCalls = true;
  6764. break;
  6765. }
  6766. this.dispatchEventToListeners("wait", hasLongRunningCalls);
  6767. for (callId in this._callbacks)
  6768. this._previousCallbacks[callId] = true;
  6769. },
  6770.  
  6771. _findFunction: function(name)
  6772. {
  6773. var path = name.split(".");
  6774. var result = window;
  6775. for (var i = 0; i < path.length; ++i)
  6776. result = result[path[i]];
  6777. return result;
  6778. },
  6779.  
  6780. _messageReceived: function(event)
  6781. {
  6782. var data = event.data;
  6783. if (event.data.error) {
  6784. if (event.data.errorMethodName)
  6785. WebInspector.log(WebInspector.UIString("An error happened when a call for method '%s' was requested", event.data.errorMethodName));
  6786. WebInspector.log(event.data.errorCallStack);
  6787. delete this._callbacks[data.callId];
  6788. return;
  6789. }
  6790. if (!this._callbacks[data.callId])
  6791. return;
  6792. var callback = this._callbacks[data.callId];
  6793. delete this._callbacks[data.callId];
  6794. callback(data.result);
  6795. },
  6796.  
  6797. _postMessage: function(message)
  6798. {
  6799. this._worker.postMessage(message);
  6800. },
  6801.  
  6802. __proto__: WebInspector.Object.prototype
  6803. }
  6804.  
  6805.  
  6806.  
  6807. WebInspector.HeapSnapshotProxyObject = function(worker, objectId)
  6808. {
  6809. this._worker = worker;
  6810. this._objectId = objectId;
  6811. }
  6812.  
  6813. WebInspector.HeapSnapshotProxyObject.prototype = {
  6814. _callWorker: function(workerMethodName, args)
  6815. {
  6816. args.splice(1, 0, this._objectId);
  6817. return this._worker[workerMethodName].apply(this._worker, args);
  6818. },
  6819.  
  6820. dispose: function()
  6821. {
  6822. this._worker.disposeObject(this._objectId);
  6823. },
  6824.  
  6825. disposeWorker: function()
  6826. {
  6827. this._worker.dispose();
  6828. },
  6829.  
  6830.  
  6831. callFactoryMethod: function(callback, methodName, proxyConstructorName, var_args)
  6832. {
  6833. return this._callWorker("callFactoryMethod", Array.prototype.slice.call(arguments, 0));
  6834. },
  6835.  
  6836. callGetter: function(callback, getterName)
  6837. {
  6838. return this._callWorker("callGetter", Array.prototype.slice.call(arguments, 0));
  6839. },
  6840.  
  6841.  
  6842. callMethod: function(callback, methodName, var_args)
  6843. {
  6844. return this._callWorker("callMethod", Array.prototype.slice.call(arguments, 0));
  6845. },
  6846.  
  6847. get worker() {
  6848. return this._worker;
  6849. }
  6850. };
  6851.  
  6852.  
  6853. WebInspector.HeapSnapshotLoaderProxy = function(worker, objectId)
  6854. {
  6855. WebInspector.HeapSnapshotProxyObject.call(this, worker, objectId);
  6856. this._pendingSnapshotConsumers = [];
  6857. }
  6858.  
  6859. WebInspector.HeapSnapshotLoaderProxy.prototype = {
  6860.  
  6861. addConsumer: function(callback)
  6862. {
  6863. this._pendingSnapshotConsumers.push(callback);
  6864. },
  6865.  
  6866.  
  6867. write: function(chunk, callback)
  6868. {
  6869. this.callMethod(callback, "write", chunk);
  6870. },
  6871.  
  6872. close: function()
  6873. {
  6874. function buildSnapshot()
  6875. {
  6876. this.callFactoryMethod(updateStaticData.bind(this), "buildSnapshot", "WebInspector.HeapSnapshotProxy");
  6877. }
  6878. function updateStaticData(snapshotProxy)
  6879. {
  6880. this.dispose();
  6881. snapshotProxy.updateStaticData(notifyPendingConsumers.bind(this));
  6882. }
  6883. function notifyPendingConsumers(snapshotProxy)
  6884. {
  6885. for (var i = 0; i < this._pendingSnapshotConsumers.length; ++i)
  6886. this._pendingSnapshotConsumers[i](snapshotProxy);
  6887. this._pendingSnapshotConsumers = [];
  6888. }
  6889. this.callMethod(buildSnapshot.bind(this), "close");
  6890. },
  6891.  
  6892. __proto__: WebInspector.HeapSnapshotProxyObject.prototype
  6893. }
  6894.  
  6895.  
  6896.  
  6897. WebInspector.HeapSnapshotProxy = function(worker, objectId)
  6898. {
  6899. WebInspector.HeapSnapshotProxyObject.call(this, worker, objectId);
  6900. }
  6901.  
  6902. WebInspector.HeapSnapshotProxy.prototype = {
  6903. aggregates: function(sortedIndexes, key, filter, callback)
  6904. {
  6905. this.callMethod(callback, "aggregates", sortedIndexes, key, filter);
  6906. },
  6907.  
  6908. aggregatesForDiff: function(callback)
  6909. {
  6910. this.callMethod(callback, "aggregatesForDiff");
  6911. },
  6912.  
  6913. calculateSnapshotDiff: function(baseSnapshotId, baseSnapshotAggregates, callback)
  6914. {
  6915. this.callMethod(callback, "calculateSnapshotDiff", baseSnapshotId, baseSnapshotAggregates);
  6916. },
  6917.  
  6918. nodeClassName: function(snapshotObjectId, callback)
  6919. {
  6920. this.callMethod(callback, "nodeClassName", snapshotObjectId);
  6921. },
  6922.  
  6923. dominatorIdsForNode: function(nodeIndex, callback)
  6924. {
  6925. this.callMethod(callback, "dominatorIdsForNode", nodeIndex);
  6926. },
  6927.  
  6928. createEdgesProvider: function(nodeIndex, filter)
  6929. {
  6930. return this.callFactoryMethod(null, "createEdgesProvider", "WebInspector.HeapSnapshotProviderProxy", nodeIndex, filter);
  6931. },
  6932.  
  6933. createRetainingEdgesProvider: function(nodeIndex, filter)
  6934. {
  6935. return this.callFactoryMethod(null, "createRetainingEdgesProvider", "WebInspector.HeapSnapshotProviderProxy", nodeIndex, filter);
  6936. },
  6937.  
  6938. createAddedNodesProvider: function(baseSnapshotId, className)
  6939. {
  6940. return this.callFactoryMethod(null, "createAddedNodesProvider", "WebInspector.HeapSnapshotProviderProxy", baseSnapshotId, className);
  6941. },
  6942.  
  6943. createDeletedNodesProvider: function(nodeIndexes)
  6944. {
  6945. return this.callFactoryMethod(null, "createDeletedNodesProvider", "WebInspector.HeapSnapshotProviderProxy", nodeIndexes);
  6946. },
  6947.  
  6948. createNodesProvider: function(filter)
  6949. {
  6950. return this.callFactoryMethod(null, "createNodesProvider", "WebInspector.HeapSnapshotProviderProxy", filter);
  6951. },
  6952.  
  6953. createNodesProviderForClass: function(className, aggregatesKey)
  6954. {
  6955. return this.callFactoryMethod(null, "createNodesProviderForClass", "WebInspector.HeapSnapshotProviderProxy", className, aggregatesKey);
  6956. },
  6957.  
  6958. createNodesProviderForDominator: function(nodeIndex)
  6959. {
  6960. return this.callFactoryMethod(null, "createNodesProviderForDominator", "WebInspector.HeapSnapshotProviderProxy", nodeIndex);
  6961. },
  6962.  
  6963. dispose: function()
  6964. {
  6965. this.disposeWorker();
  6966. },
  6967.  
  6968. get nodeCount()
  6969. {
  6970. return this._staticData.nodeCount;
  6971. },
  6972.  
  6973. get nodeFlags()
  6974. {
  6975. return this._staticData.nodeFlags;
  6976. },
  6977.  
  6978. get rootNodeIndex()
  6979. {
  6980. return this._staticData.rootNodeIndex;
  6981. },
  6982.  
  6983. updateStaticData: function(callback)
  6984. {
  6985. function dataReceived(staticData)
  6986. {
  6987. this._staticData = staticData;
  6988. callback(this);
  6989. }
  6990. this.callMethod(dataReceived.bind(this), "updateStaticData");
  6991. },
  6992.  
  6993. get totalSize()
  6994. {
  6995. return this._staticData.totalSize;
  6996. },
  6997.  
  6998. get uid()
  6999. {
  7000. return this._staticData.uid;
  7001. },
  7002.  
  7003. __proto__: WebInspector.HeapSnapshotProxyObject.prototype
  7004. }
  7005.  
  7006.  
  7007.  
  7008. WebInspector.HeapSnapshotProviderProxy = function(worker, objectId)
  7009. {
  7010. WebInspector.HeapSnapshotProxyObject.call(this, worker, objectId);
  7011. }
  7012.  
  7013. WebInspector.HeapSnapshotProviderProxy.prototype = {
  7014. nodePosition: function(snapshotObjectId, callback)
  7015. {
  7016. this.callMethod(callback, "nodePosition", snapshotObjectId);
  7017. },
  7018.  
  7019. isEmpty: function(callback)
  7020. {
  7021. this.callMethod(callback, "isEmpty");
  7022. },
  7023.  
  7024. serializeItemsRange: function(startPosition, endPosition, callback)
  7025. {
  7026. this.callMethod(callback, "serializeItemsRange", startPosition, endPosition);
  7027. },
  7028.  
  7029. sortAndRewind: function(comparator, callback)
  7030. {
  7031. this.callMethod(callback, "sortAndRewind", comparator);
  7032. },
  7033.  
  7034. __proto__: WebInspector.HeapSnapshotProxyObject.prototype
  7035. }
  7036.  
  7037. ;
  7038.  
  7039.  
  7040.  
  7041. WebInspector.HeapSnapshotView = function(parent, profile)
  7042. {
  7043. WebInspector.View.call(this);
  7044.  
  7045. this.element.addStyleClass("heap-snapshot-view");
  7046.  
  7047. this.parent = parent;
  7048. this.parent.addEventListener("profile added", this._updateBaseOptions, this);
  7049. this.parent.addEventListener("profile added", this._updateFilterOptions, this);
  7050.  
  7051. this.viewsContainer = document.createElement("div");
  7052. this.viewsContainer.addStyleClass("views-container");
  7053. this.element.appendChild(this.viewsContainer);
  7054.  
  7055. this.containmentView = new WebInspector.View();
  7056. this.containmentView.element.addStyleClass("view");
  7057. this.containmentDataGrid = new WebInspector.HeapSnapshotContainmentDataGrid();
  7058. this.containmentDataGrid.element.addEventListener("mousedown", this._mouseDownInContentsGrid.bind(this), true);
  7059. this.containmentDataGrid.show(this.containmentView.element);
  7060. this.containmentDataGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNode, this._selectionChanged, this);
  7061.  
  7062. this.constructorsView = new WebInspector.View();
  7063. this.constructorsView.element.addStyleClass("view");
  7064. this.constructorsView.element.appendChild(this._createToolbarWithClassNameFilter());
  7065.  
  7066. this.constructorsDataGrid = new WebInspector.HeapSnapshotConstructorsDataGrid();
  7067. this.constructorsDataGrid.element.addStyleClass("class-view-grid");
  7068. this.constructorsDataGrid.element.addEventListener("mousedown", this._mouseDownInContentsGrid.bind(this), true);
  7069. this.constructorsDataGrid.show(this.constructorsView.element);
  7070. this.constructorsDataGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNode, this._selectionChanged, this);
  7071.  
  7072. this.diffView = new WebInspector.View();
  7073. this.diffView.element.addStyleClass("view");
  7074. this.diffView.element.appendChild(this._createToolbarWithClassNameFilter());
  7075.  
  7076. this.diffDataGrid = new WebInspector.HeapSnapshotDiffDataGrid();
  7077. this.diffDataGrid.element.addStyleClass("class-view-grid");
  7078. this.diffDataGrid.show(this.diffView.element);
  7079. this.diffDataGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNode, this._selectionChanged, this);
  7080.  
  7081. this.dominatorView = new WebInspector.View();
  7082. this.dominatorView.element.addStyleClass("view");
  7083. this.dominatorDataGrid = new WebInspector.HeapSnapshotDominatorsDataGrid();
  7084. this.dominatorDataGrid.element.addEventListener("mousedown", this._mouseDownInContentsGrid.bind(this), true);
  7085. this.dominatorDataGrid.show(this.dominatorView.element);
  7086. this.dominatorDataGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNode, this._selectionChanged, this);
  7087.  
  7088. this.retainmentViewHeader = document.createElement("div");
  7089. this.retainmentViewHeader.addStyleClass("retainers-view-header");
  7090. WebInspector.installDragHandle(this.retainmentViewHeader, this._startRetainersHeaderDragging.bind(this), this._retainersHeaderDragging.bind(this), this._endRetainersHeaderDragging.bind(this), "row-resize");
  7091. var retainingPathsTitleDiv = document.createElement("div");
  7092. retainingPathsTitleDiv.className = "title";
  7093. var retainingPathsTitle = document.createElement("span");
  7094. retainingPathsTitle.textContent = WebInspector.UIString("Object's retaining tree");
  7095. retainingPathsTitleDiv.appendChild(retainingPathsTitle);
  7096. this.retainmentViewHeader.appendChild(retainingPathsTitleDiv);
  7097. this.element.appendChild(this.retainmentViewHeader);
  7098.  
  7099. this.retainmentView = new WebInspector.View();
  7100. this.retainmentView.element.addStyleClass("view");
  7101. this.retainmentView.element.addStyleClass("retaining-paths-view");
  7102. this.retainmentDataGrid = new WebInspector.HeapSnapshotRetainmentDataGrid();
  7103. this.retainmentDataGrid.show(this.retainmentView.element);
  7104. this.retainmentDataGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNode, this._inspectedObjectChanged, this);
  7105. this.retainmentView.show(this.element);
  7106. this.retainmentDataGrid.reset();
  7107.  
  7108. this.dataGrid = this.constructorsDataGrid;
  7109. this.currentView = this.constructorsView;
  7110.  
  7111. this.viewSelectElement = document.createElement("select");
  7112. this.viewSelectElement.className = "status-bar-item";
  7113. this.viewSelectElement.addEventListener("change", this._onSelectedViewChanged.bind(this), false);
  7114.  
  7115. this.views = [{title: "Summary", view: this.constructorsView, grid: this.constructorsDataGrid},
  7116. {title: "Comparison", view: this.diffView, grid: this.diffDataGrid},
  7117. {title: "Containment", view: this.containmentView, grid: this.containmentDataGrid},
  7118. {title: "Dominators", view: this.dominatorView, grid: this.dominatorDataGrid}];
  7119. this.views.current = 0;
  7120. for (var i = 0; i < this.views.length; ++i) {
  7121. var view = this.views[i];
  7122. var option = document.createElement("option");
  7123. option.label = WebInspector.UIString(view.title);
  7124. this.viewSelectElement.appendChild(option);
  7125. }
  7126.  
  7127. this._profileUid = profile.uid;
  7128.  
  7129. this.baseSelectElement = document.createElement("select");
  7130. this.baseSelectElement.className = "status-bar-item";
  7131. this.baseSelectElement.addEventListener("change", this._changeBase.bind(this), false);
  7132. this._updateBaseOptions();
  7133.  
  7134. this.filterSelectElement = document.createElement("select");
  7135. this.filterSelectElement.className = "status-bar-item";
  7136. this.filterSelectElement.addEventListener("change", this._changeFilter.bind(this), false);
  7137. this._updateFilterOptions();
  7138.  
  7139. this.helpButton = new WebInspector.StatusBarButton("", "heap-snapshot-help-status-bar-item status-bar-item");
  7140. this.helpButton.addEventListener("click", this._helpClicked, this);
  7141.  
  7142. this._popoverHelper = new WebInspector.ObjectPopoverHelper(this.element, this._getHoverAnchor.bind(this), this._resolveObjectForPopover.bind(this), undefined, true);
  7143.  
  7144. this.profile.load(profileCallback.bind(this));
  7145.  
  7146. function profileCallback(heapSnapshotProxy)
  7147. {
  7148. var list = this._profiles();
  7149. var profileIndex;
  7150. for (var i = 0; i < list.length; ++i) {
  7151. if (list[i].uid === this._profileUid) {
  7152. profileIndex = i;
  7153. break;
  7154. }
  7155. }
  7156.  
  7157. if (profileIndex > 0)
  7158. this.baseSelectElement.selectedIndex = profileIndex - 1;
  7159. else
  7160. this.baseSelectElement.selectedIndex = profileIndex;
  7161. this.dataGrid.setDataSource(this, heapSnapshotProxy);
  7162. }
  7163. }
  7164.  
  7165. WebInspector.HeapSnapshotView.prototype = {
  7166. dispose: function()
  7167. {
  7168. this.profile.dispose();
  7169. if (this.baseProfile)
  7170. this.baseProfile.dispose();
  7171. this.containmentDataGrid.dispose();
  7172. this.constructorsDataGrid.dispose();
  7173. this.diffDataGrid.dispose();
  7174. this.dominatorDataGrid.dispose();
  7175. this.retainmentDataGrid.dispose();
  7176. },
  7177.  
  7178. get statusBarItems()
  7179. {
  7180.  
  7181. function appendArrowImage(element, hidden)
  7182. {
  7183. var span = document.createElement("span");
  7184. span.className = "status-bar-select-container" + (hidden ? " hidden" : "");
  7185. span.appendChild(element);
  7186. return span;
  7187. }
  7188. return [appendArrowImage(this.viewSelectElement), appendArrowImage(this.baseSelectElement, true), appendArrowImage(this.filterSelectElement), this.helpButton.element];
  7189. },
  7190.  
  7191. get profile()
  7192. {
  7193. return this.parent.getProfile(WebInspector.HeapSnapshotProfileType.TypeId, this._profileUid);
  7194. },
  7195.  
  7196. get baseProfile()
  7197. {
  7198. return this.parent.getProfile(WebInspector.HeapSnapshotProfileType.TypeId, this._baseProfileUid);
  7199. },
  7200.  
  7201. wasShown: function()
  7202. {
  7203.  
  7204. this.profile.load(profileCallback1.bind(this));
  7205.  
  7206. function profileCallback1() {
  7207. if (this.baseProfile)
  7208. this.baseProfile.load(profileCallback2.bind(this));
  7209. else
  7210. profileCallback2.call(this);
  7211. }
  7212.  
  7213. function profileCallback2() {
  7214. this.currentView.show(this.viewsContainer);
  7215. }
  7216. },
  7217.  
  7218. willHide: function()
  7219. {
  7220. this._currentSearchResultIndex = -1;
  7221. this._popoverHelper.hidePopover();
  7222. if (this.helpPopover && this.helpPopover.isShowing())
  7223. this.helpPopover.hide();
  7224. },
  7225.  
  7226. onResize: function()
  7227. {
  7228. var height = this.retainmentView.element.clientHeight;
  7229. this._updateRetainmentViewHeight(height);
  7230. },
  7231.  
  7232. searchCanceled: function()
  7233. {
  7234. if (this._searchResults) {
  7235. for (var i = 0; i < this._searchResults.length; ++i) {
  7236. var node = this._searchResults[i].node;
  7237. delete node._searchMatched;
  7238. node.refresh();
  7239. }
  7240. }
  7241.  
  7242. delete this._searchFinishedCallback;
  7243. this._currentSearchResultIndex = -1;
  7244. this._searchResults = [];
  7245. },
  7246.  
  7247. performSearch: function(query, finishedCallback)
  7248. {
  7249.  
  7250. this.searchCanceled();
  7251.  
  7252. query = query.trim();
  7253.  
  7254. if (!query.length)
  7255. return;
  7256. if (this.currentView !== this.constructorsView && this.currentView !== this.diffView)
  7257. return;
  7258.  
  7259. this._searchFinishedCallback = finishedCallback;
  7260.  
  7261. function matchesByName(gridNode) {
  7262. return ("_name" in gridNode) && gridNode._name.hasSubstring(query, true);
  7263. }
  7264.  
  7265. function matchesById(gridNode) {
  7266. return ("snapshotNodeId" in gridNode) && gridNode.snapshotNodeId === query;
  7267. }
  7268.  
  7269. var matchPredicate;
  7270. if (query.charAt(0) !== "@")
  7271. matchPredicate = matchesByName;
  7272. else {
  7273. query = parseInt(query.substring(1), 10);
  7274. matchPredicate = matchesById;
  7275. }
  7276.  
  7277. function matchesQuery(gridNode)
  7278. {
  7279. delete gridNode._searchMatched;
  7280. if (matchPredicate(gridNode)) {
  7281. gridNode._searchMatched = true;
  7282. gridNode.refresh();
  7283. return true;
  7284. }
  7285. return false;
  7286. }
  7287.  
  7288. var current = this.dataGrid.rootNode().children[0];
  7289. var depth = 0;
  7290. var info = {};
  7291.  
  7292.  
  7293. const maxDepth = 1;
  7294.  
  7295. while (current) {
  7296. if (matchesQuery(current))
  7297. this._searchResults.push({ node: current });
  7298. current = current.traverseNextNode(false, null, (depth >= maxDepth), info);
  7299. depth += info.depthChange;
  7300. }
  7301.  
  7302. finishedCallback(this, this._searchResults.length);
  7303. },
  7304.  
  7305. jumpToFirstSearchResult: function()
  7306. {
  7307. if (!this._searchResults || !this._searchResults.length)
  7308. return;
  7309. this._currentSearchResultIndex = 0;
  7310. this._jumpToSearchResult(this._currentSearchResultIndex);
  7311. },
  7312.  
  7313. jumpToLastSearchResult: function()
  7314. {
  7315. if (!this._searchResults || !this._searchResults.length)
  7316. return;
  7317. this._currentSearchResultIndex = (this._searchResults.length - 1);
  7318. this._jumpToSearchResult(this._currentSearchResultIndex);
  7319. },
  7320.  
  7321. jumpToNextSearchResult: function()
  7322. {
  7323. if (!this._searchResults || !this._searchResults.length)
  7324. return;
  7325. if (++this._currentSearchResultIndex >= this._searchResults.length)
  7326. this._currentSearchResultIndex = 0;
  7327. this._jumpToSearchResult(this._currentSearchResultIndex);
  7328. },
  7329.  
  7330. jumpToPreviousSearchResult: function()
  7331. {
  7332. if (!this._searchResults || !this._searchResults.length)
  7333. return;
  7334. if (--this._currentSearchResultIndex < 0)
  7335. this._currentSearchResultIndex = (this._searchResults.length - 1);
  7336. this._jumpToSearchResult(this._currentSearchResultIndex);
  7337. },
  7338.  
  7339. showingFirstSearchResult: function()
  7340. {
  7341. return (this._currentSearchResultIndex === 0);
  7342. },
  7343.  
  7344. showingLastSearchResult: function()
  7345. {
  7346. return (this._searchResults && this._currentSearchResultIndex === (this._searchResults.length - 1));
  7347. },
  7348.  
  7349. _jumpToSearchResult: function(index)
  7350. {
  7351. var searchResult = this._searchResults[index];
  7352. if (!searchResult)
  7353. return;
  7354.  
  7355. var node = searchResult.node;
  7356. node.revealAndSelect();
  7357. },
  7358.  
  7359. refreshVisibleData: function()
  7360. {
  7361. var child = this.dataGrid.rootNode().children[0];
  7362. while (child) {
  7363. child.refresh();
  7364. child = child.traverseNextNode(false, null, true);
  7365. }
  7366. },
  7367.  
  7368. _changeBase: function()
  7369. {
  7370. if (this._baseProfileUid === this._profiles()[this.baseSelectElement.selectedIndex].uid)
  7371. return;
  7372.  
  7373. this._baseProfileUid = this._profiles()[this.baseSelectElement.selectedIndex].uid;
  7374. var dataGrid =   (this.dataGrid);
  7375.  
  7376. if (dataGrid.snapshot)
  7377. this.baseProfile.load(dataGrid.setBaseDataSource.bind(dataGrid));
  7378.  
  7379. if (!this.currentQuery || !this._searchFinishedCallback || !this._searchResults)
  7380. return;
  7381.  
  7382.  
  7383.  
  7384.  
  7385. this._searchFinishedCallback(this, -this._searchResults.length);
  7386. this.performSearch(this.currentQuery, this._searchFinishedCallback);
  7387. },
  7388.  
  7389. _changeFilter: function()
  7390. {
  7391. var profileIndex = this.filterSelectElement.selectedIndex - 1;
  7392. this.dataGrid._filterSelectIndexChanged(this._profiles(), profileIndex);
  7393.  
  7394. if (!this.currentQuery || !this._searchFinishedCallback || !this._searchResults)
  7395. return;
  7396.  
  7397.  
  7398.  
  7399.  
  7400. this._searchFinishedCallback(this, -this._searchResults.length);
  7401. this.performSearch(this.currentQuery, this._searchFinishedCallback);
  7402. },
  7403.  
  7404. _createToolbarWithClassNameFilter: function()
  7405. {
  7406. var toolbar = document.createElement("div");
  7407. toolbar.addStyleClass("class-view-toolbar");
  7408. var classNameFilter = document.createElement("input");
  7409. classNameFilter.addStyleClass("class-name-filter");
  7410. classNameFilter.setAttribute("placeholder", WebInspector.UIString("Class filter"));
  7411. classNameFilter.addEventListener("keyup", this._changeNameFilter.bind(this, classNameFilter), false);
  7412. toolbar.appendChild(classNameFilter);
  7413. return toolbar;
  7414. },
  7415.  
  7416. _changeNameFilter: function(classNameInputElement)
  7417. {
  7418. var filter = classNameInputElement.value;
  7419. this.dataGrid.changeNameFilter(filter);
  7420. },
  7421.  
  7422. _profiles: function()
  7423. {
  7424. return this.parent.getProfiles(WebInspector.HeapSnapshotProfileType.TypeId);
  7425. },
  7426.  
  7427. processLoadedSnapshot: function(profile, snapshot)
  7428. {
  7429. profile.nodes = snapshot.nodes;
  7430. profile.strings = snapshot.strings;
  7431. var s = new WebInspector.HeapSnapshot(profile);
  7432. profile.sidebarElement.subtitle = Number.bytesToString(s.totalSize);
  7433. },
  7434.  
  7435.  
  7436. populateContextMenu: function(contextMenu, event)
  7437. {
  7438. this.dataGrid.populateContextMenu(this.parent, contextMenu, event);
  7439. },
  7440.  
  7441. _selectionChanged: function(event)
  7442. {
  7443. var selectedNode = event.target.selectedNode;
  7444. this._setRetainmentDataGridSource(selectedNode);
  7445. this._inspectedObjectChanged(event);
  7446. },
  7447.  
  7448. _inspectedObjectChanged: function(event)
  7449. {
  7450. var selectedNode = event.target.selectedNode;
  7451. if (!this.profile.fromFile() && selectedNode instanceof WebInspector.HeapSnapshotGenericObjectNode)
  7452. ConsoleAgent.addInspectedHeapObject(selectedNode.snapshotNodeId);
  7453. },
  7454.  
  7455. _setRetainmentDataGridSource: function(nodeItem)
  7456. {
  7457. if (nodeItem && nodeItem.snapshotNodeIndex)
  7458. this.retainmentDataGrid.setDataSource(this, nodeItem.isDeletedNode ? nodeItem.dataGrid.baseSnapshot : nodeItem.dataGrid.snapshot, nodeItem.snapshotNodeIndex);
  7459. else
  7460. this.retainmentDataGrid.reset();
  7461. },
  7462.  
  7463. _mouseDownInContentsGrid: function(event)
  7464. {
  7465. if (event.detail < 2)
  7466. return;
  7467.  
  7468. var cell = event.target.enclosingNodeOrSelfWithNodeName("td");
  7469. if (!cell || (!cell.hasStyleClass("count-column") && !cell.hasStyleClass("shallowSize-column") && !cell.hasStyleClass("retainedSize-column")))
  7470. return;
  7471.  
  7472. event.consume(true);
  7473. },
  7474.  
  7475. changeView: function(viewTitle, callback)
  7476. {
  7477. var viewIndex = null;
  7478. for (var i = 0; i < this.views.length; ++i)
  7479. if (this.views[i].title === viewTitle) {
  7480. viewIndex = i;
  7481. break;
  7482. }
  7483. if (this.views.current === viewIndex) {
  7484. setTimeout(callback, 0);
  7485. return;
  7486. }
  7487.  
  7488. function dataGridContentShown(event)
  7489. {
  7490. var dataGrid = event.data;
  7491. dataGrid.removeEventListener(WebInspector.HeapSnapshotSortableDataGrid.Events.ContentShown, dataGridContentShown, this);
  7492. if (dataGrid === this.dataGrid)
  7493. callback();
  7494. }
  7495. this.views[viewIndex].grid.addEventListener(WebInspector.HeapSnapshotSortableDataGrid.Events.ContentShown, dataGridContentShown, this);
  7496.  
  7497. this.viewSelectElement.selectedIndex = viewIndex;
  7498. this._changeView(viewIndex);
  7499. },
  7500.  
  7501. _updateDataSourceAndView: function()
  7502. {
  7503. var dataGrid = this.dataGrid;
  7504. if (dataGrid.snapshotView)
  7505. return;
  7506.  
  7507. this.profile.load(didLoadSnapshot.bind(this));
  7508. function didLoadSnapshot(snapshotProxy)
  7509. {
  7510. if (this.dataGrid !== dataGrid)
  7511. return;
  7512. if (dataGrid.snapshot !== snapshotProxy)
  7513. dataGrid.setDataSource(this, snapshotProxy);
  7514. if (dataGrid === this.diffDataGrid) {
  7515. if (!this._baseProfileUid)
  7516. this._baseProfileUid = this._profiles()[this.baseSelectElement.selectedIndex].uid;
  7517. this.baseProfile.load(didLoadBaseSnaphot.bind(this));
  7518. }
  7519. }
  7520.  
  7521. function didLoadBaseSnaphot(baseSnapshotProxy)
  7522. {
  7523. if (this.diffDataGrid.baseSnapshot !== baseSnapshotProxy)
  7524. this.diffDataGrid.setBaseDataSource(baseSnapshotProxy);
  7525. }
  7526. },
  7527.  
  7528. _onSelectedViewChanged: function(event)
  7529. {
  7530. this._changeView(event.target.selectedIndex);
  7531. },
  7532.  
  7533. _updateSelectorsVisibility: function()
  7534. {
  7535. if (this.currentView === this.diffView)
  7536. this.baseSelectElement.parentElement.removeStyleClass("hidden");
  7537. else
  7538. this.baseSelectElement.parentElement.addStyleClass("hidden");
  7539.  
  7540. if (this.currentView === this.constructorsView)
  7541. this.filterSelectElement.parentElement.removeStyleClass("hidden");
  7542. else
  7543. this.filterSelectElement.parentElement.addStyleClass("hidden");
  7544. },
  7545.  
  7546. _changeView: function(selectedIndex)
  7547. {
  7548. if (selectedIndex === this.views.current)
  7549. return;
  7550.  
  7551. this.views.current = selectedIndex;
  7552. this.currentView.detach();
  7553. var view = this.views[this.views.current];
  7554. this.currentView = view.view;
  7555. this.dataGrid = view.grid;
  7556. this.currentView.show(this.viewsContainer);
  7557. this.refreshVisibleData();
  7558. this.dataGrid.updateWidths();
  7559.  
  7560. this._updateSelectorsVisibility();
  7561.  
  7562. this._updateDataSourceAndView();
  7563.  
  7564. if (!this.currentQuery || !this._searchFinishedCallback || !this._searchResults)
  7565. return;
  7566.  
  7567.  
  7568.  
  7569.  
  7570. this._searchFinishedCallback(this, -this._searchResults.length);
  7571. this.performSearch(this.currentQuery, this._searchFinishedCallback);
  7572. },
  7573.  
  7574. _getHoverAnchor: function(target)
  7575. {
  7576. var span = target.enclosingNodeOrSelfWithNodeName("span");
  7577. if (!span)
  7578. return;
  7579. var row = target.enclosingNodeOrSelfWithNodeName("tr");
  7580. if (!row)
  7581. return;
  7582. span.node = row._dataGridNode;
  7583. return span;
  7584. },
  7585.  
  7586. _resolveObjectForPopover: function(element, showCallback, objectGroupName)
  7587. {
  7588. if (this.profile.fromFile())
  7589. return;
  7590. element.node.queryObjectContent(showCallback, objectGroupName);
  7591. },
  7592.  
  7593. _helpClicked: function(event)
  7594. {
  7595. if (!this._helpPopoverContentElement) {
  7596. var refTypes = ["a:", "console-formatted-name", WebInspector.UIString("property"),
  7597. "0:", "console-formatted-name", WebInspector.UIString("element"),
  7598. "a:", "console-formatted-number", WebInspector.UIString("context var"),
  7599. "a:", "console-formatted-null", WebInspector.UIString("system prop")];
  7600. var objTypes = [" a ", "console-formatted-object", "Object",
  7601. "\"a\"", "console-formatted-string", "String",
  7602. "/a/", "console-formatted-string", "RegExp",
  7603. "a()", "console-formatted-function", "Function",
  7604. "a[]", "console-formatted-object", "Array",
  7605. "num", "console-formatted-number", "Number",
  7606. " a ", "console-formatted-null", "System"];
  7607.  
  7608. var contentElement = document.createElement("table");
  7609. contentElement.className = "heap-snapshot-help";
  7610. var headerRow = document.createElement("tr");
  7611. var propsHeader = document.createElement("th");
  7612. propsHeader.textContent = WebInspector.UIString("Property types:");
  7613. headerRow.appendChild(propsHeader);
  7614. var objsHeader = document.createElement("th");
  7615. objsHeader.textContent = WebInspector.UIString("Object types:");
  7616. headerRow.appendChild(objsHeader);
  7617. contentElement.appendChild(headerRow);
  7618.  
  7619. function appendHelp(help, index, cell)
  7620. {
  7621. var div = document.createElement("div");
  7622. div.className = "source-code event-properties";
  7623. var name = document.createElement("span");
  7624. name.textContent = help[index];
  7625. name.className = help[index + 1];
  7626. div.appendChild(name);
  7627. var desc = document.createElement("span");
  7628. desc.textContent = " " + help[index + 2];
  7629. div.appendChild(desc);
  7630. cell.appendChild(div);
  7631. }
  7632.  
  7633. var len = Math.max(refTypes.length, objTypes.length);
  7634. for (var i = 0; i < len; i += 3) {
  7635. var row = document.createElement("tr");
  7636. var refCell = document.createElement("td");
  7637. if (refTypes[i])
  7638. appendHelp(refTypes, i, refCell);
  7639. row.appendChild(refCell);
  7640. var objCell = document.createElement("td");
  7641. if (objTypes[i])
  7642. appendHelp(objTypes, i, objCell);
  7643. row.appendChild(objCell);
  7644. contentElement.appendChild(row);
  7645. }
  7646. this._helpPopoverContentElement = contentElement;
  7647. this.helpPopover = new WebInspector.Popover();
  7648. }
  7649. if (this.helpPopover.isShowing())
  7650. this.helpPopover.hide();
  7651. else
  7652. this.helpPopover.show(this._helpPopoverContentElement, this.helpButton.element);
  7653. },
  7654.  
  7655.  
  7656. _startRetainersHeaderDragging: function(event)
  7657. {
  7658. if (!this.isShowing())
  7659. return false;
  7660.  
  7661. this._previousDragPosition = event.pageY;
  7662. return true;
  7663. },
  7664.  
  7665. _retainersHeaderDragging: function(event)
  7666. {
  7667. var height = this.retainmentView.element.clientHeight;
  7668. height += this._previousDragPosition - event.pageY;
  7669. this._previousDragPosition = event.pageY;
  7670. this._updateRetainmentViewHeight(height);
  7671. event.consume(true);
  7672. },
  7673.  
  7674. _endRetainersHeaderDragging: function(event)
  7675. {
  7676. delete this._previousDragPosition;
  7677. event.consume();
  7678. },
  7679.  
  7680. _updateRetainmentViewHeight: function(height)
  7681. {
  7682. height = Number.constrain(height, Preferences.minConsoleHeight, this.element.clientHeight - Preferences.minConsoleHeight);
  7683. this.viewsContainer.style.bottom = (height + this.retainmentViewHeader.clientHeight) + "px";
  7684. this.retainmentView.element.style.height = height + "px";
  7685. this.retainmentViewHeader.style.bottom = height + "px";
  7686. },
  7687.  
  7688. _updateBaseOptions: function()
  7689. {
  7690. var list = this._profiles();
  7691.  
  7692. if (this.baseSelectElement.length === list.length)
  7693. return;
  7694.  
  7695. for (var i = this.baseSelectElement.length, n = list.length; i < n; ++i) {
  7696. var baseOption = document.createElement("option");
  7697. var title = list[i].title;
  7698. if (!title.indexOf(UserInitiatedProfileName))
  7699. title = WebInspector.UIString("Snapshot %d", title.substring(UserInitiatedProfileName.length + 1));
  7700. baseOption.label = title;
  7701. this.baseSelectElement.appendChild(baseOption);
  7702. }
  7703. },
  7704.  
  7705. _updateFilterOptions: function()
  7706. {
  7707. var list = this._profiles();
  7708.  
  7709. if (this.filterSelectElement.length - 1 === list.length)
  7710. return;
  7711.  
  7712. if (!this.filterSelectElement.length) {
  7713. var filterOption = document.createElement("option");
  7714. filterOption.label = WebInspector.UIString("All objects");
  7715. this.filterSelectElement.appendChild(filterOption);
  7716. }
  7717.  
  7718. if (this.profile.fromFile())
  7719. return;
  7720. for (var i = this.filterSelectElement.length - 1, n = list.length; i < n; ++i) {
  7721. var profile = list[i];
  7722. var filterOption = document.createElement("option");
  7723. var title = list[i].title;
  7724. if (!title.indexOf(UserInitiatedProfileName)) {
  7725. if (!i)
  7726. title = WebInspector.UIString("Objects allocated before Snapshot %d", title.substring(UserInitiatedProfileName.length + 1));
  7727. else
  7728. title = WebInspector.UIString("Objects allocated between Snapshots %d and %d", title.substring(UserInitiatedProfileName.length + 1) - 1, title.substring(UserInitiatedProfileName.length + 1));
  7729. }
  7730. filterOption.label = title;
  7731. this.filterSelectElement.appendChild(filterOption);
  7732. }
  7733. },
  7734.  
  7735. __proto__: WebInspector.View.prototype
  7736. }
  7737.  
  7738.  
  7739.  
  7740. WebInspector.HeapSnapshotProfileType = function()
  7741. {
  7742. WebInspector.ProfileType.call(this, WebInspector.HeapSnapshotProfileType.TypeId, WebInspector.UIString("Take Heap Snapshot"));
  7743. }
  7744.  
  7745. WebInspector.HeapSnapshotProfileType.TypeId = "HEAP";
  7746.  
  7747. WebInspector.HeapSnapshotProfileType.prototype = {
  7748. get buttonTooltip()
  7749. {
  7750. return WebInspector.UIString("Take heap snapshot.");
  7751. },
  7752.  
  7753.  
  7754. buttonClicked: function(profilesPanel)
  7755. {
  7756. profilesPanel.takeHeapSnapshot();
  7757. return false;
  7758. },
  7759.  
  7760. get treeItemTitle()
  7761. {
  7762. return WebInspector.UIString("HEAP SNAPSHOTS");
  7763. },
  7764.  
  7765. get description()
  7766. {
  7767. return WebInspector.UIString("Heap snapshot profiles show memory distribution among your page's JavaScript objects and related DOM nodes.");
  7768. },
  7769.  
  7770.  
  7771. createTemporaryProfile: function(title)
  7772. {
  7773. title = title || WebInspector.UIString("Snapshotting\u2026");
  7774. return new WebInspector.HeapProfileHeader(this, title);
  7775. },
  7776.  
  7777.  
  7778. createProfile: function(profile)
  7779. {
  7780. return new WebInspector.HeapProfileHeader(this, profile.title, profile.uid, profile.maxJSObjectId || 0);
  7781. },
  7782.  
  7783. __proto__: WebInspector.ProfileType.prototype
  7784. }
  7785.  
  7786.  
  7787. WebInspector.HeapProfileHeader = function(type, title, uid, maxJSObjectId)
  7788. {
  7789. WebInspector.ProfileHeader.call(this, type, title, uid);
  7790. this.maxJSObjectId = maxJSObjectId;
  7791.  
  7792. this._receiver = null;
  7793.  
  7794. this._snapshotProxy = null;
  7795. this._totalNumberOfChunks = 0;
  7796. }
  7797.  
  7798. WebInspector.HeapProfileHeader.prototype = {
  7799.  
  7800. createSidebarTreeElement: function()
  7801. {
  7802. return new WebInspector.ProfileSidebarTreeElement(this, WebInspector.UIString("Snapshot %d"), "heap-snapshot-sidebar-tree-item");
  7803. },
  7804.  
  7805.  
  7806. createView: function(profilesPanel)
  7807. {
  7808. return new WebInspector.HeapSnapshotView(profilesPanel, this);
  7809. },
  7810.  
  7811. snapshotProxy: function()
  7812. {
  7813. return this._snapshotProxy;
  7814. },
  7815.  
  7816.  
  7817. load: function(callback)
  7818. {
  7819. if (this._snapshotProxy) {
  7820. callback(this._snapshotProxy);
  7821. return;
  7822. }
  7823.  
  7824. this._numberOfChunks = 0;
  7825. this._savedChunks = 0;
  7826. this._savingToFile = false;
  7827. if (!this._receiver) {
  7828. this._setupWorker();
  7829. this.sidebarElement.subtitle = WebInspector.UIString("Loading\u2026");
  7830. this.sidebarElement.wait = true;
  7831. ProfilerAgent.getProfile(this.profileType().id, this.uid);
  7832. }
  7833. var loaderProxy =   (this._receiver);
  7834. loaderProxy.addConsumer(callback);
  7835. },
  7836.  
  7837. _setupWorker: function()
  7838. {
  7839. function setProfileWait(event)
  7840. {
  7841. this.sidebarElement.wait = event.data;
  7842. }
  7843. var worker = new WebInspector.HeapSnapshotWorker();
  7844. worker.addEventListener("wait", setProfileWait, this);
  7845. var loaderProxy = worker.createObject("WebInspector.HeapSnapshotLoader");
  7846. loaderProxy.addConsumer(this._snapshotReceived.bind(this));
  7847. this._receiver = loaderProxy;
  7848. },
  7849.  
  7850. dispose: function()
  7851. {
  7852. if (this._receiver)
  7853. this._receiver.close();
  7854. else if (this._snapshotProxy)
  7855. this._snapshotProxy.dispose();
  7856. },
  7857.  
  7858.  
  7859. _updateTransferProgress: function(value, maxValue)
  7860. {
  7861. var percentValue = ((maxValue ? (value / maxValue) : 0) * 100).toFixed(2);
  7862. if (this._savingToFile)
  7863. this.sidebarElement.subtitle = WebInspector.UIString("Saving\u2026 %d\%", percentValue);
  7864. else
  7865. this.sidebarElement.subtitle = WebInspector.UIString("Loading\u2026 %d\%", percentValue);
  7866. },
  7867.  
  7868. _updateSnapshotStatus: function()
  7869. {
  7870. this.sidebarElement.subtitle = Number.bytesToString(this._snapshotProxy.totalSize);
  7871. this.sidebarElement.wait = false;
  7872. },
  7873.  
  7874.  
  7875. transferChunk: function(chunk)
  7876. {
  7877. ++this._numberOfChunks;
  7878. this._receiver.write(chunk, callback.bind(this));
  7879. function callback()
  7880. {
  7881. this._updateTransferProgress(++this._savedChunks, this._totalNumberOfChunks);
  7882. if (this._totalNumberOfChunks === this._savedChunks) {
  7883. if (this._savingToFile)
  7884. this._updateSnapshotStatus();
  7885. else
  7886. this.sidebarElement.subtitle = WebInspector.UIString("Parsing\u2026");
  7887.  
  7888. this._receiver.close();
  7889. }
  7890. }
  7891. },
  7892.  
  7893. _snapshotReceived: function(snapshotProxy)
  7894. {
  7895. this._receiver = null;
  7896. if (snapshotProxy)
  7897. this._snapshotProxy = snapshotProxy;
  7898. this._updateSnapshotStatus();
  7899. var worker =   (this._snapshotProxy.worker);
  7900. this.isTemporary = false;
  7901. worker.startCheckingForLongRunningCalls();
  7902. },
  7903.  
  7904. finishHeapSnapshot: function()
  7905. {
  7906. this._totalNumberOfChunks = this._numberOfChunks;
  7907. },
  7908.  
  7909.  
  7910. canSaveToFile: function()
  7911. {
  7912. return !this.fromFile() && !!this._snapshotProxy && !this._receiver;
  7913. },
  7914.  
  7915.  
  7916. saveToFile: function()
  7917. {
  7918. this._numberOfChunks = 0;
  7919. function onOpen()
  7920. {
  7921. this._savedChunks = 0;
  7922. this._updateTransferProgress(0, this._totalNumberOfChunks);
  7923. ProfilerAgent.getProfile(this.profileType().id, this.uid);
  7924. }
  7925. this._savingToFile = true;
  7926. this._fileName = this._fileName || "Heap-" + new Date().toISO8601Compact() + ".heapsnapshot";
  7927. this._receiver = new WebInspector.FileOutputStream();
  7928. this._receiver.open(this._fileName, onOpen.bind(this));
  7929. },
  7930.  
  7931.  
  7932. canLoadFromFile: function()
  7933. {
  7934. return false;
  7935. },
  7936.  
  7937.  
  7938. loadFromFile: function(file)
  7939. {
  7940. this.title = file.name;
  7941. this.sidebarElement.subtitle = WebInspector.UIString("Loading\u2026");
  7942. this.sidebarElement.wait = true;
  7943. this._setupWorker();
  7944. this._numberOfChunks = 0;
  7945. this._savingToFile = false;
  7946.  
  7947. var delegate = new WebInspector.HeapSnapshotLoadFromFileDelegate(this);
  7948. var fileReader = this._createFileReader(file, delegate);
  7949. fileReader.start(this._receiver);
  7950. },
  7951.  
  7952. _createFileReader: function(file, delegate)
  7953. {
  7954. return new WebInspector.ChunkedFileReader(file, 10000000, delegate);
  7955. },
  7956.  
  7957. __proto__: WebInspector.ProfileHeader.prototype
  7958. }
  7959.  
  7960.  
  7961. WebInspector.HeapSnapshotLoadFromFileDelegate = function(snapshotHeader)
  7962. {
  7963. this._snapshotHeader = snapshotHeader;
  7964. }
  7965.  
  7966. WebInspector.HeapSnapshotLoadFromFileDelegate.prototype = {
  7967. onTransferStarted: function()
  7968. {
  7969. },
  7970.  
  7971.  
  7972. onChunkTransferred: function(reader)
  7973. {
  7974. this._snapshotHeader._updateTransferProgress(reader.loadedSize(), reader.fileSize());
  7975. },
  7976.  
  7977. onTransferFinished: function()
  7978. {
  7979. this._snapshotHeader.finishHeapSnapshot();
  7980. },
  7981.  
  7982.  
  7983. onError: function (reader, e)
  7984. {
  7985. switch(e.target.error.code) {
  7986. case e.target.error.NOT_FOUND_ERR:
  7987. this._snapshotHeader.sidebarElement.subtitle = WebInspector.UIString("'%s' not found.", reader.fileName());
  7988. break;
  7989. case e.target.error.NOT_READABLE_ERR:
  7990. this._snapshotHeader.sidebarElement.subtitle = WebInspector.UIString("'%s' is not readable", reader.fileName());
  7991. break;
  7992. case e.target.error.ABORT_ERR:
  7993. break;
  7994. default:
  7995. this._snapshotHeader.sidebarElement.subtitle = WebInspector.UIString("'%s' error %d", reader.fileName(), e.target.error.code);
  7996. }
  7997. }
  7998. }
  7999. ;
  8000.  
  8001.  
  8002.  
  8003. WebInspector.HeapSnapshotWorkerDispatcher = function(globalObject, postMessage)
  8004. {
  8005. this._objects = [];
  8006. this._global = globalObject;
  8007. this._postMessage = postMessage;
  8008. }
  8009.  
  8010. WebInspector.HeapSnapshotWorkerDispatcher.prototype = {
  8011. _findFunction: function(name)
  8012. {
  8013. var path = name.split(".");
  8014. var result = this._global;
  8015. for (var i = 0; i < path.length; ++i)
  8016. result = result[path[i]];
  8017. return result;
  8018. },
  8019.  
  8020. dispatchMessage: function(event)
  8021. {
  8022. var data = event.data;
  8023. var response = {callId: data.callId};
  8024. try {
  8025. switch (data.disposition) {
  8026. case "create": {
  8027. var constructorFunction = this._findFunction(data.methodName);
  8028. this._objects[data.objectId] = new constructorFunction();
  8029. break;
  8030. }
  8031. case "dispose": {
  8032. delete this._objects[data.objectId];
  8033. break;
  8034. }
  8035. case "getter": {
  8036. var object = this._objects[data.objectId];
  8037. var result = object[data.methodName];
  8038. response.result = result;
  8039. break;
  8040. }
  8041. case "factory": {
  8042. var object = this._objects[data.objectId];
  8043. var result = object[data.methodName].apply(object, data.methodArguments);
  8044. if (result)
  8045. this._objects[data.newObjectId] = result;
  8046. response.result = !!result;
  8047. break;
  8048. }
  8049. case "method": {
  8050. var object = this._objects[data.objectId];
  8051. response.result = object[data.methodName].apply(object, data.methodArguments);
  8052. break;
  8053. }
  8054. }
  8055. } catch (e) {
  8056. response.error = e.toString();
  8057. response.errorCallStack = e.stack;
  8058. if (data.methodName)
  8059. response.errorMethodName = data.methodName;
  8060. }
  8061. this._postMessage(response);
  8062. }
  8063. };
  8064. ;
  8065.  
  8066.  
  8067.  
  8068. WebInspector.NativeMemorySnapshotView = function(profile)
  8069. {
  8070. WebInspector.View.call(this);
  8071. this.registerRequiredCSS("nativeMemoryProfiler.css");
  8072.  
  8073. this.element.addStyleClass("native-snapshot-view");
  8074. this.containmentDataGrid = new WebInspector.NativeSnapshotDataGrid(profile._memoryBlock);
  8075. this.containmentDataGrid.show(this.element);
  8076. }
  8077.  
  8078. WebInspector.NativeMemorySnapshotView.prototype = {
  8079. __proto__: WebInspector.View.prototype
  8080. }
  8081.  
  8082.  
  8083. WebInspector.NativeSnapshotDataGrid = function(profile)
  8084. {
  8085. var columns = {
  8086. object: { title: WebInspector.UIString("Object"), width: "200px", disclosure: true, sortable: false },
  8087. size: { title: WebInspector.UIString("Size"), sortable: false },
  8088. };
  8089. WebInspector.DataGrid.call(this, columns);
  8090. this.setRootNode(new WebInspector.DataGridNode(null, true));
  8091. var totalNode = new WebInspector.NativeSnapshotNode(profile, profile);
  8092. this.rootNode().appendChild(totalNode);
  8093. totalNode.expand();
  8094. }
  8095.  
  8096. WebInspector.NativeSnapshotDataGrid.prototype = {
  8097. __proto__: WebInspector.DataGrid.prototype
  8098. }
  8099.  
  8100.  
  8101. WebInspector.NativeSnapshotNode = function(nodeData, profile)
  8102. {
  8103. this._nodeData = nodeData;
  8104. this._profile = profile;
  8105. var viewProperties = WebInspector.MemoryBlockViewProperties._forMemoryBlock(nodeData);
  8106. var data = { object: viewProperties._description, size: this._nodeData.size };
  8107. var hasChildren = !!nodeData.children && nodeData.children.length !== 0;
  8108. WebInspector.DataGridNode.call(this, data, hasChildren);
  8109. this.addEventListener("populate", this._populate, this);
  8110. }
  8111.  
  8112. WebInspector.NativeSnapshotNode.prototype = {
  8113.  
  8114. createCell: function(columnIdentifier)
  8115. {
  8116. var cell = columnIdentifier === "size" ?
  8117. this._createSizeCell(columnIdentifier) :
  8118. WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier);
  8119. return cell;
  8120. },
  8121.  
  8122.  
  8123. _createSizeCell: function(columnIdentifier)
  8124. {
  8125. var node = this;
  8126. var viewProperties = null;
  8127. while (!viewProperties || viewProperties._fillStyle === "inherit") {
  8128. viewProperties = WebInspector.MemoryBlockViewProperties._forMemoryBlock(node._nodeData);
  8129. node = node.parent;
  8130. }
  8131.  
  8132. var sizeKiB = this._nodeData.size / 1024;
  8133. var totalSize = this._profile.size;
  8134. var percentage = this._nodeData.size / totalSize  * 100;
  8135.  
  8136. var cell = document.createElement("td");
  8137. cell.className = columnIdentifier + "-column";
  8138.  
  8139. var textDiv = document.createElement("div");
  8140. textDiv.textContent = Number.withThousandsSeparator(sizeKiB.toFixed(0)) + "\u2009" + WebInspector.UIString("KiB");
  8141. textDiv.className = "size-text";
  8142. cell.appendChild(textDiv);
  8143.  
  8144. var barDiv = document.createElement("div");
  8145. barDiv.className = "size-bar";
  8146. barDiv.style.width = percentage + "%";
  8147. barDiv.style.backgroundColor = viewProperties._fillStyle;
  8148.  
  8149. var fillerDiv = document.createElement("div");
  8150. fillerDiv.className = "percent-text"
  8151. barDiv.appendChild(fillerDiv);
  8152. var percentDiv = document.createElement("div");
  8153. percentDiv.textContent = percentage.toFixed(1) + "%";
  8154. percentDiv.className = "percent-text"
  8155. barDiv.appendChild(percentDiv);
  8156.  
  8157. var barHolderDiv = document.createElement("div");
  8158. barHolderDiv.appendChild(barDiv);
  8159. cell.appendChild(barHolderDiv);
  8160.  
  8161. return cell;
  8162. },
  8163.  
  8164. _populate: function() {
  8165. this.removeEventListener("populate", this._populate, this);
  8166. function comparator(a, b) {
  8167. return b.size - a.size;
  8168. }
  8169. if (this._nodeData !== this._profile)
  8170. this._nodeData.children.sort(comparator);
  8171. for (var node in this._nodeData.children) {
  8172. this.appendChild(new WebInspector.NativeSnapshotNode(this._nodeData.children[node], this._profile));
  8173. }
  8174. },
  8175.  
  8176. __proto__: WebInspector.DataGridNode.prototype
  8177. }
  8178.  
  8179.  
  8180. WebInspector.NativeMemoryProfileType = function()
  8181. {
  8182. WebInspector.ProfileType.call(this, WebInspector.NativeMemoryProfileType.TypeId, WebInspector.UIString("Take Native Memory Snapshot"));
  8183. this._nextProfileUid = 1;
  8184. }
  8185.  
  8186. WebInspector.NativeMemoryProfileType.TypeId = "NATIVE_MEMORY";
  8187.  
  8188. WebInspector.NativeMemoryProfileType.prototype = {
  8189. get buttonTooltip()
  8190. {
  8191. return WebInspector.UIString("Take native memory snapshot.");
  8192. },
  8193.  
  8194.  
  8195. buttonClicked: function(profilesPanel)
  8196. {
  8197. var profileHeader = new WebInspector.NativeMemoryProfileHeader(this, WebInspector.UIString("Snapshot %d", this._nextProfileUid), this._nextProfileUid);
  8198. ++this._nextProfileUid;
  8199. profileHeader.isTemporary = true;
  8200. profilesPanel.addProfileHeader(profileHeader);
  8201. function didReceiveMemorySnapshot(error, memoryBlock)
  8202. {
  8203. if (memoryBlock.size && memoryBlock.children) {
  8204. var knownSize = 0;
  8205. for (var i = 0; i < memoryBlock.children.length; i++) {
  8206. var size = memoryBlock.children[i].size;
  8207. if (size)
  8208. knownSize += size;
  8209. }
  8210. var otherSize = memoryBlock.size - knownSize;
  8211.  
  8212. if (otherSize) {
  8213. memoryBlock.children.push({
  8214. name: "Other",
  8215. size: otherSize
  8216. });
  8217. }
  8218. }
  8219. profileHeader._memoryBlock = memoryBlock;
  8220. profileHeader.isTemporary = false;
  8221. }
  8222. MemoryAgent.getProcessMemoryDistribution(didReceiveMemorySnapshot.bind(this));
  8223. return false;
  8224. },
  8225.  
  8226. get treeItemTitle()
  8227. {
  8228. return WebInspector.UIString("MEMORY DISTRIBUTION");
  8229. },
  8230.  
  8231. get description()
  8232. {
  8233. return WebInspector.UIString("Native memory snapshot profiles show memory distribution among browser subsystems");
  8234. },
  8235.  
  8236.  
  8237. createTemporaryProfile: function(title)
  8238. {
  8239. title = title || WebInspector.UIString("Snapshotting\u2026");
  8240. return new WebInspector.NativeMemoryProfileHeader(this, title);
  8241. },
  8242.  
  8243.  
  8244. createProfile: function(profile)
  8245. {
  8246. return new WebInspector.NativeMemoryProfileHeader(this, profile.title, -1);
  8247. },
  8248.  
  8249. __proto__: WebInspector.ProfileType.prototype
  8250. }
  8251.  
  8252.  
  8253. WebInspector.NativeMemoryProfileHeader = function(type, title, uid)
  8254. {
  8255. WebInspector.ProfileHeader.call(this, type, title, uid);
  8256.  
  8257.  
  8258. this._memoryBlock = null;
  8259. }
  8260.  
  8261. WebInspector.NativeMemoryProfileHeader.prototype = {
  8262.  
  8263. createSidebarTreeElement: function()
  8264. {
  8265. return new WebInspector.ProfileSidebarTreeElement(this, WebInspector.UIString("Snapshot %d"), "heap-snapshot-sidebar-tree-item");
  8266. },
  8267.  
  8268.  
  8269. createView: function(profilesPanel)
  8270. {
  8271. return new WebInspector.NativeMemorySnapshotView(this);
  8272. },
  8273.  
  8274. __proto__: WebInspector.ProfileHeader.prototype
  8275. }
  8276.  
  8277.  
  8278. WebInspector.MemoryBlockViewProperties = function(fillStyle, name, description)
  8279. {
  8280. this._fillStyle = fillStyle;
  8281. this._name = name;
  8282. this._description = description;
  8283. }
  8284.  
  8285.  
  8286. WebInspector.MemoryBlockViewProperties._standardBlocks = null;
  8287.  
  8288. WebInspector.MemoryBlockViewProperties._initialize = function()
  8289. {
  8290. if (WebInspector.MemoryBlockViewProperties._standardBlocks)
  8291. return;
  8292. WebInspector.MemoryBlockViewProperties._standardBlocks = {};
  8293. function addBlock(fillStyle, name, description)
  8294. {
  8295. WebInspector.MemoryBlockViewProperties._standardBlocks[name] = new WebInspector.MemoryBlockViewProperties(fillStyle, name, WebInspector.UIString(description));
  8296. }
  8297. addBlock("hsl(  0,  0%,  60%)", "ProcessPrivateMemory", "Total");
  8298. addBlock("hsl(  0,  0%,  80%)", "OwnersTypePlaceholder", "OwnersTypePlaceholder");
  8299. addBlock("hsl(  0,  0%,  60%)", "Other", "Other");
  8300. addBlock("hsl(220, 80%,  70%)", "Page", "Page structures");
  8301. addBlock("hsl(100, 60%,  50%)", "JSHeap", "JavaScript heap");
  8302. addBlock("hsl( 90, 40%,  80%)", "JSExternalResources", "JavaScript external resources");
  8303. addBlock("hsl( 90, 60%,  80%)", "JSExternalArrays", "JavaScript external arrays");
  8304. addBlock("hsl( 90, 60%,  80%)", "JSExternalStrings", "JavaScript external strings");
  8305. addBlock("hsl(  0, 80%,  60%)", "WebInspector", "Inspector data");
  8306. addBlock("hsl( 36, 90%,  50%)", "MemoryCache", "Memory cache resources");
  8307. addBlock("hsl( 40, 80%,  80%)", "GlyphCache", "Glyph cache resources");
  8308. addBlock("hsl( 35, 80%,  80%)", "DOMStorageCache", "DOM storage cache");
  8309. addBlock("hsl( 60, 80%,  60%)", "RenderTree", "Render tree");
  8310. }
  8311.  
  8312. WebInspector.MemoryBlockViewProperties._forMemoryBlock = function(memoryBlock)
  8313. {
  8314. WebInspector.MemoryBlockViewProperties._initialize();
  8315. var result = WebInspector.MemoryBlockViewProperties._standardBlocks[memoryBlock.name];
  8316. if (result)
  8317. return result;
  8318. return new WebInspector.MemoryBlockViewProperties("inherit", memoryBlock.name, memoryBlock.name);
  8319. }
  8320.  
  8321.  
  8322.  
  8323. WebInspector.NativeMemoryPieChart = function(memorySnapshot)
  8324. {
  8325. WebInspector.View.call(this);
  8326. this._memorySnapshot = memorySnapshot;
  8327. this.element = document.createElement("div");
  8328. this.element.addStyleClass("memory-pie-chart-container");
  8329. this._memoryBlockList = this.element.createChild("div", "memory-blocks-list");
  8330.  
  8331. this._canvasContainer = this.element.createChild("div", "memory-pie-chart");
  8332. this._canvas = this._canvasContainer.createChild("canvas");
  8333. this._addBlockLabels(memorySnapshot, true);
  8334. }
  8335.  
  8336. WebInspector.NativeMemoryPieChart.prototype = {
  8337.  
  8338. onResize: function()
  8339. {
  8340. this._updateSize();
  8341. this._paint();
  8342. },
  8343.  
  8344. _updateSize: function()
  8345. {
  8346. var width = this._canvasContainer.clientWidth - 5;
  8347. var height = this._canvasContainer.clientHeight - 5;
  8348. this._canvas.width = width;
  8349. this._canvas.height = height;
  8350. },
  8351.  
  8352. _addBlockLabels: function(memoryBlock, includeChildren)
  8353. {
  8354. var viewProperties = WebInspector.MemoryBlockViewProperties._forMemoryBlock(memoryBlock);
  8355. var title = viewProperties._description + ": " + Number.bytesToString(memoryBlock.size);
  8356.  
  8357. var swatchElement = this._memoryBlockList.createChild("div", "item");
  8358. swatchElement.createChild("div", "swatch").style.backgroundColor = viewProperties._fillStyle;
  8359. swatchElement.createChild("span", "title").textContent = title;
  8360.  
  8361. if (!memoryBlock.children || !includeChildren)
  8362. return;
  8363. for (var i = 0; i < memoryBlock.children.length; i++)
  8364. this._addBlockLabels(memoryBlock.children[i], false);
  8365. },
  8366.  
  8367. _paint: function()
  8368. {
  8369. this._clear();
  8370. var width = this._canvas.width;
  8371. var height = this._canvas.height;
  8372.  
  8373. var x = width / 2;
  8374. var y = height / 2;
  8375. var radius = 200;
  8376.  
  8377. var ctx = this._canvas.getContext("2d");
  8378. ctx.beginPath();
  8379. ctx.arc(x, y, radius, 0, Math.PI*2, false);
  8380. ctx.lineWidth = 1;
  8381. ctx.strokeStyle = "rgba(130, 130, 130, 0.8)";
  8382. ctx.stroke();
  8383. ctx.closePath();
  8384.  
  8385. var currentAngle = 0;
  8386. var memoryBlock = this._memorySnapshot;
  8387.  
  8388. function paintPercentAndLabel(fraction, title, midAngle)
  8389. {
  8390. ctx.beginPath();
  8391. ctx.font = "13px Arial";
  8392. ctx.fillStyle = "rgba(10, 10, 10, 0.8)";
  8393.  
  8394. var textX = x + (radius + 10) * Math.cos(midAngle);
  8395. var textY = y + (radius + 10) * Math.sin(midAngle);
  8396. var relativeOffset = -Math.cos(midAngle) / Math.sin(Math.PI / 12);
  8397. relativeOffset = Number.constrain(relativeOffset, -1, 1);
  8398. var metrics = ctx.measureText(title);
  8399. textX -= metrics.width * (relativeOffset + 1) / 2;
  8400. textY += 5;
  8401. ctx.fillText(title, textX, textY);
  8402.  
  8403.  
  8404. if (fraction > 0.03) {
  8405. textX = x + radius * Math.cos(midAngle) / 2;
  8406. textY = y + radius * Math.sin(midAngle) / 2;
  8407. ctx.fillText((100 * fraction).toFixed(0) + "%", textX - 8, textY + 5);
  8408. }
  8409.  
  8410. ctx.closePath();
  8411. }
  8412.  
  8413. if (!memoryBlock.children)
  8414. return;
  8415. var total = memoryBlock.size;
  8416. for (var i = 0; i < memoryBlock.children.length; i++) {
  8417. var child = memoryBlock.children[i];
  8418. if (!child.size)
  8419. continue;
  8420. var viewProperties = WebInspector.MemoryBlockViewProperties._forMemoryBlock(child);
  8421. var angleSpan = Math.PI * 2 * (child.size / total);
  8422. ctx.beginPath();
  8423. ctx.moveTo(x, y);
  8424. ctx.lineTo(x + radius * Math.cos(currentAngle), y + radius * Math.sin(currentAngle));
  8425. ctx.arc(x, y, radius, currentAngle, currentAngle + angleSpan, false);
  8426. ctx.lineWidth = 0.5;
  8427. ctx.lineTo(x, y);
  8428. ctx.fillStyle = viewProperties._fillStyle;
  8429. ctx.strokeStyle = "rgba(100, 100, 100, 0.8)";
  8430. ctx.fill();
  8431. ctx.stroke();
  8432. ctx.closePath();
  8433.  
  8434. paintPercentAndLabel(child.size / total, viewProperties._description, currentAngle + angleSpan / 2);
  8435.  
  8436. currentAngle += angleSpan;
  8437. }
  8438. },
  8439.  
  8440. _clear: function() {
  8441. var ctx = this._canvas.getContext("2d");
  8442. ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  8443. },
  8444.  
  8445. __proto__: WebInspector.View.prototype
  8446. }
  8447.  
  8448.  
  8449. WebInspector.NativeMemoryBarChart = function()
  8450. {
  8451. WebInspector.View.call(this);
  8452. this.registerRequiredCSS("nativeMemoryProfiler.css");
  8453. this._memorySnapshot = null;
  8454. this.element = document.createElement("div");
  8455. this._table = this.element.createChild("table");
  8456. this._divs = {};
  8457. var row = this._table.insertRow();
  8458. this._totalDiv = row.insertCell().createChild("div");
  8459. this._totalDiv.addStyleClass("memory-bar-chart-total");
  8460. row.insertCell();
  8461. }
  8462.  
  8463. WebInspector.NativeMemoryBarChart.prototype = {
  8464. _updateStats: function()
  8465. {
  8466. function didReceiveMemorySnapshot(error, memoryBlock)
  8467. {
  8468. if (memoryBlock.size && memoryBlock.children) {
  8469. var knownSize = 0;
  8470. for (var i = 0; i < memoryBlock.children.length; i++) {
  8471. var size = memoryBlock.children[i].size;
  8472. if (size)
  8473. knownSize += size;
  8474. }
  8475. var otherSize = memoryBlock.size - knownSize;
  8476.  
  8477. if (otherSize) {
  8478. memoryBlock.children.push({
  8479. name: "Other",
  8480. size: otherSize
  8481. });
  8482. }
  8483. }
  8484. this._memorySnapshot = memoryBlock;
  8485. this._updateView();
  8486. }
  8487. MemoryAgent.getProcessMemoryDistribution(didReceiveMemorySnapshot.bind(this));
  8488. },
  8489.  
  8490.  
  8491. willHide: function()
  8492. {
  8493. clearInterval(this._timerId);
  8494. },
  8495.  
  8496.  
  8497. wasShown: function()
  8498. {
  8499. this._timerId = setInterval(this._updateStats.bind(this), 1000);
  8500. },
  8501.  
  8502. _updateView: function()
  8503. {
  8504. var memoryBlock = this._memorySnapshot;
  8505. if (!memoryBlock)
  8506. return;
  8507.  
  8508. var MB = 1024 * 1024;
  8509. var maxSize = 100 * MB;
  8510. for (var i = 0; i < memoryBlock.children.length; ++i)
  8511. maxSize = Math.max(maxSize, memoryBlock.children[i].size);
  8512. var maxBarLength = 500;
  8513. var barLengthSizeRatio = maxBarLength / maxSize;
  8514.  
  8515. for (var i = memoryBlock.children.length - 1; i >= 0 ; --i) {
  8516. var child = memoryBlock.children[i];
  8517. var name = child.name;
  8518. var divs = this._divs[name];
  8519. if (!divs) {
  8520. var row = this._table.insertRow();
  8521. var nameDiv = row.insertCell(-1).createChild("div");
  8522. var viewProperties = WebInspector.MemoryBlockViewProperties._forMemoryBlock(child);
  8523. var title = viewProperties._description;
  8524. nameDiv.textContent = title;
  8525. nameDiv.addStyleClass("memory-bar-chart-name");
  8526. var barCell = row.insertCell(-1);
  8527. var barDiv = barCell.createChild("div");
  8528. barDiv.addStyleClass("memory-bar-chart-bar");
  8529. viewProperties = WebInspector.MemoryBlockViewProperties._forMemoryBlock(child);
  8530. barDiv.style.backgroundColor = viewProperties._fillStyle;
  8531. var unusedDiv = barDiv.createChild("div");
  8532. unusedDiv.addStyleClass("memory-bar-chart-unused");
  8533. var percentDiv = barDiv.createChild("div");
  8534. percentDiv.addStyleClass("memory-bar-chart-percent");
  8535. var sizeDiv = barCell.createChild("div");
  8536. sizeDiv.addStyleClass("memory-bar-chart-size");
  8537. divs = this._divs[name] = { barDiv: barDiv, unusedDiv: unusedDiv, percentDiv: percentDiv, sizeDiv: sizeDiv };
  8538. }
  8539. var unusedSize = 0;
  8540. if (!!child.children) {
  8541. var unusedName = name + ".Unused";
  8542. for (var j = 0; j < child.children.length; ++j) {
  8543. if (child.children[j].name === unusedName) {
  8544. unusedSize = child.children[j].size;
  8545. break;
  8546. }
  8547. }
  8548. }
  8549. var unusedLength = unusedSize * barLengthSizeRatio;
  8550. var barLength = child.size * barLengthSizeRatio;
  8551.  
  8552. divs.barDiv.style.width = barLength + "px";
  8553. divs.unusedDiv.style.width = unusedLength + "px";
  8554. divs.percentDiv.textContent = barLength > 20 ? (child.size / memoryBlock.size * 100).toFixed(0) + "%" : "";
  8555. divs.sizeDiv.textContent = (child.size / MB).toFixed(1) + "\u2009MB";
  8556. }
  8557.  
  8558. var memoryBlockViewProperties = WebInspector.MemoryBlockViewProperties._forMemoryBlock(memoryBlock);
  8559. this._totalDiv.textContent = memoryBlockViewProperties._description + ": " + (memoryBlock.size / MB).toFixed(1) + "\u2009MB";
  8560. },
  8561.  
  8562. __proto__: WebInspector.View.prototype
  8563. }
  8564. ;
  8565.  
  8566.  
  8567.  
  8568. WebInspector.ProfileLauncherView = function(profilesPanel)
  8569. {
  8570. WebInspector.View.call(this);
  8571.  
  8572. this._panel = profilesPanel;
  8573. this._profileRunning = false;
  8574.  
  8575. this.element.addStyleClass("profile-launcher-view");
  8576. this.element.addStyleClass("panel-enabler-view");
  8577.  
  8578. this._contentElement = document.createElement("div");
  8579. this._contentElement.className = "profile-launcher-view-content";
  8580. this.element.appendChild(this._contentElement);
  8581.  
  8582. var header = this._contentElement.createChild("h1");
  8583. header.textContent = WebInspector.UIString("Select profiling type");
  8584.  
  8585. this._profileTypeSelectorForm = this._contentElement.createChild("form");
  8586.  
  8587. if (WebInspector.experimentsSettings.liveNativeMemoryChart.isEnabled()) {
  8588. this._nativeMemoryElement = document.createElement("div");
  8589. this._contentElement.appendChild(this._nativeMemoryElement);
  8590. this._nativeMemoryLiveChart = new WebInspector.NativeMemoryBarChart();
  8591. this._nativeMemoryLiveChart.show(this._nativeMemoryElement);
  8592. }
  8593.  
  8594. this._contentElement.createChild("div", "flexible-space");
  8595.  
  8596. this._controlButton = this._contentElement.createChild("button", "control-profiling");
  8597. this._controlButton.addEventListener("click", this._controlButtonClicked.bind(this), false);
  8598. this._updateControls();
  8599. }
  8600.  
  8601. WebInspector.ProfileLauncherView.EventTypes = {
  8602. ProfileTypeSelected: "profile-type-selected"
  8603. }
  8604.  
  8605. WebInspector.ProfileLauncherView.prototype = {
  8606.  
  8607. addProfileType: function(profileType)
  8608. {
  8609. var checked = !this._profileTypeSelectorForm.children.length;
  8610. var labelElement = this._profileTypeSelectorForm.createChild("label");
  8611. labelElement.textContent = profileType.name;
  8612. var optionElement = document.createElement("input");
  8613. labelElement.insertBefore(optionElement, labelElement.firstChild);
  8614. optionElement.type = "radio";
  8615. optionElement.name = "profile-type";
  8616. if (checked) {
  8617. optionElement.checked = checked;
  8618. this.dispatchEventToListeners(WebInspector.ProfileLauncherView.EventTypes.ProfileTypeSelected, profileType);
  8619. }
  8620. optionElement.addEventListener("change", this._profileTypeChanged.bind(this, profileType), false);
  8621. var descriptionElement = labelElement.createChild("p");
  8622. descriptionElement.textContent = profileType.description;
  8623. },
  8624.  
  8625. _controlButtonClicked: function()
  8626. {
  8627. this._panel.toggleRecordButton();
  8628. },
  8629.  
  8630. _updateControls: function()
  8631. {
  8632. if (this._isProfiling) {
  8633. this._profileTypeSelectorForm.disabled = true;
  8634. this._controlButton.addStyleClass("running");
  8635. this._controlButton.textContent = WebInspector.UIString("Stop");
  8636. } else {
  8637. this._profileTypeSelectorForm.disabled = false;
  8638. this._controlButton.removeStyleClass("running");
  8639. this._controlButton.textContent = WebInspector.UIString("Start");
  8640. }
  8641. },
  8642.  
  8643.  
  8644. _profileTypeChanged: function(profileType, event)
  8645. {
  8646. this.dispatchEventToListeners(WebInspector.ProfileLauncherView.EventTypes.ProfileTypeSelected, profileType);
  8647. },
  8648.  
  8649. profileStarted: function()
  8650. {
  8651. this._isProfiling = true;
  8652. this._updateControls();
  8653. },
  8654.  
  8655. profileFinished: function()
  8656. {
  8657. this._isProfiling = false;
  8658. this._updateControls();
  8659. },
  8660.  
  8661. __proto__: WebInspector.View.prototype
  8662. }
  8663. ;
  8664.  
  8665.  
  8666.  
  8667. WebInspector.TopDownProfileDataGridNode = function(  profileView,   profileNode,   owningTree)
  8668. {
  8669. var hasChildren = (profileNode.children && profileNode.children.length);
  8670.  
  8671. WebInspector.ProfileDataGridNode.call(this, profileView, profileNode, owningTree, hasChildren);
  8672.  
  8673. this._remainingChildren = profileNode.children;
  8674. }
  8675.  
  8676. WebInspector.TopDownProfileDataGridNode.prototype = {
  8677. _sharedPopulate: function()
  8678. {
  8679. var children = this._remainingChildren;
  8680. var childrenLength = children.length;
  8681.  
  8682. for (var i = 0; i < childrenLength; ++i)
  8683. this.appendChild(new WebInspector.TopDownProfileDataGridNode(this.profileView, children[i], this.tree));
  8684.  
  8685. this._remainingChildren = null;
  8686. },
  8687.  
  8688. _exclude: function(aCallUID)
  8689. {
  8690. if (this._remainingChildren)
  8691. this._populate();
  8692.  
  8693. this._save();
  8694.  
  8695. var children = this.children;
  8696. var index = this.children.length;
  8697.  
  8698. while (index--)
  8699. children[index]._exclude(aCallUID);
  8700.  
  8701. var child = this.childrenByCallUID[aCallUID];
  8702.  
  8703. if (child)
  8704. this._merge(child, true);
  8705. },
  8706.  
  8707. __proto__: WebInspector.ProfileDataGridNode.prototype
  8708. }
  8709.  
  8710.  
  8711. WebInspector.TopDownProfileDataGridTree = function(  profileView,   profileNode)
  8712. {
  8713. WebInspector.ProfileDataGridTree.call(this, profileView, profileNode);
  8714.  
  8715. this._remainingChildren = profileNode.children;
  8716.  
  8717. var any =  this;
  8718. var node =  any;
  8719. WebInspector.TopDownProfileDataGridNode.prototype._populate.call(node);
  8720. }
  8721.  
  8722. WebInspector.TopDownProfileDataGridTree.prototype = {
  8723. focus: function(  profileDataGrideNode)
  8724. {
  8725. if (!profileDataGrideNode)
  8726. return;
  8727.  
  8728. this._save();
  8729. profileDataGrideNode.savePosition();
  8730.  
  8731. this.children = [profileDataGrideNode];
  8732. this.totalTime = profileDataGrideNode.totalTime;
  8733. },
  8734.  
  8735. exclude: function(  profileDataGrideNode)
  8736. {
  8737. if (!profileDataGrideNode)
  8738. return;
  8739.  
  8740. this._save();
  8741.  
  8742. var excludedCallUID = profileDataGrideNode.callUID;
  8743.  
  8744. var any =  this;
  8745. var node =  any;
  8746. WebInspector.TopDownProfileDataGridNode.prototype._exclude.call(node, excludedCallUID);
  8747.  
  8748. if (this.lastComparator)
  8749. this.sort(this.lastComparator, true);
  8750. },
  8751.  
  8752. restore: function()
  8753. {
  8754. if (!this._savedChildren)
  8755. return;
  8756.  
  8757. this.children[0].restorePosition();
  8758.  
  8759. WebInspector.ProfileDataGridTree.prototype.restore.call(this);
  8760. },
  8761.  
  8762. _merge: WebInspector.TopDownProfileDataGridNode.prototype._merge,
  8763.  
  8764. _sharedPopulate: WebInspector.TopDownProfileDataGridNode.prototype._sharedPopulate,
  8765.  
  8766. __proto__: WebInspector.ProfileDataGridTree.prototype
  8767. }
  8768. ;
  8769.  
  8770.  
  8771.  
  8772. WebInspector.CanvasProfileView = function(profile)
  8773. {
  8774. WebInspector.View.call(this);
  8775. this.registerRequiredCSS("canvasProfiler.css");
  8776. this._profile = profile;
  8777. this._traceLogId = profile.traceLogId();
  8778. this.element.addStyleClass("canvas-profile-view");
  8779.  
  8780. this._splitView = new WebInspector.SplitView(false, "canvasProfileViewSplitLocation", 300);
  8781.  
  8782. this._linkifier = new WebInspector.Linkifier();
  8783. this._logGrid = new WebInspector.CanvasLogGrid(profile.traceLogId(), this._linkifier);
  8784. this._logGrid.show(this._splitView.secondElement());
  8785.  
  8786. var replayImageContainer = this._splitView.firstElement();
  8787. replayImageContainer.id = "canvas-replay-image-container";
  8788.  
  8789. this._replayImageElement = document.createElement("image");
  8790. this._replayImageElement.id = "canvas-replay-image";
  8791.  
  8792. replayImageContainer.appendChild(this._replayImageElement);
  8793. this._debugInfoElement = document.createElement("div");
  8794. replayImageContainer.appendChild(this._debugInfoElement);
  8795.  
  8796. this._splitView.show(this.element);
  8797. this._logGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNode, this._onSelectTraceLog.bind(this));
  8798. }
  8799.  
  8800. WebInspector.CanvasProfileView.prototype = {
  8801. dispose: function()
  8802. {
  8803. this._linkifier.reset();
  8804. CanvasAgent.dropTraceLog(this._profile.traceLogId());
  8805. },
  8806.  
  8807. get statusBarItems()
  8808. {
  8809. return [];
  8810. },
  8811.  
  8812. get profile()
  8813. {
  8814. return this._profile;
  8815. },
  8816.  
  8817.  
  8818. _onSelectTraceLog: function(e)
  8819. {
  8820. this._replayTraceLog(this._logGrid.selectedNode);
  8821. },
  8822.  
  8823. _replayTraceLog: function(callNode)
  8824. {
  8825. if (!callNode)
  8826. return;
  8827.  
  8828. var time = Date.now();
  8829. function didReplayTraceLog(error, dataURL)
  8830. {
  8831. if (error)
  8832. return;
  8833. this._debugInfoElement.textContent = "Replay time: " + (Date.now() - time) + "ms";
  8834. this._replayImageElement.src = dataURL;
  8835. }
  8836. CanvasAgent.replayTraceLog(this._traceLogId, callNode.index, didReplayTraceLog.bind(this));
  8837. },
  8838.  
  8839. __proto__: WebInspector.View.prototype
  8840. }
  8841.  
  8842.  
  8843. WebInspector.CanvasProfileType = function()
  8844. {
  8845. WebInspector.ProfileType.call(this, WebInspector.CanvasProfileType.TypeId, WebInspector.UIString("Capture Canvas Frame"));
  8846. this._nextProfileUid = 1;
  8847.  
  8848. CanvasAgent.enable();
  8849. }
  8850.  
  8851. WebInspector.CanvasProfileType.TypeId = "CANVAS_PROFILE";
  8852.  
  8853. WebInspector.CanvasProfileType.prototype = {
  8854. get buttonTooltip()
  8855. {
  8856. return WebInspector.UIString("Capture Canvas Frame.");
  8857. },
  8858.  
  8859.  
  8860. buttonClicked: function(profilesPanel)
  8861. {
  8862. var profileHeader = new WebInspector.CanvasProfileHeader(this, WebInspector.UIString("Trace Log %d", this._nextProfileUid), this._nextProfileUid);
  8863. ++this._nextProfileUid;
  8864. profileHeader.isTemporary = true;
  8865. profilesPanel.addProfileHeader(profileHeader);
  8866. function didStartCapturingFrame(error, traceLogId)
  8867. {
  8868. profileHeader._traceLogId = traceLogId;
  8869. profileHeader.isTemporary = false;
  8870. }
  8871. CanvasAgent.captureFrame(didStartCapturingFrame.bind(this));
  8872. return false;
  8873. },
  8874.  
  8875. get treeItemTitle()
  8876. {
  8877. return WebInspector.UIString("CANVAS PROFILE");
  8878. },
  8879.  
  8880. get description()
  8881. {
  8882. return WebInspector.UIString("Canvas calls instrumentation");
  8883. },
  8884.  
  8885.  
  8886. reset: function()
  8887. {
  8888. this._nextProfileUid = 1;
  8889. },
  8890.  
  8891.  
  8892. createTemporaryProfile: function(title)
  8893. {
  8894. title = title || WebInspector.UIString("Capturing\u2026");
  8895. return new WebInspector.CanvasProfileHeader(this, title);
  8896. },
  8897.  
  8898.  
  8899. createProfile: function(profile)
  8900. {
  8901. return new WebInspector.CanvasProfileHeader(this, profile.title, -1);
  8902. },
  8903.  
  8904. __proto__: WebInspector.ProfileType.prototype
  8905. }
  8906.  
  8907.  
  8908. WebInspector.CanvasProfileHeader = function(type, title, uid)
  8909. {
  8910. WebInspector.ProfileHeader.call(this, type, title, uid);
  8911.  
  8912.  
  8913. this._traceLogId = null;
  8914. }
  8915.  
  8916. WebInspector.CanvasProfileHeader.prototype = {
  8917.  
  8918. traceLogId: function()
  8919. {
  8920. return this._traceLogId;
  8921. },
  8922.  
  8923.  
  8924. createSidebarTreeElement: function()
  8925. {
  8926. return new WebInspector.ProfileSidebarTreeElement(this, WebInspector.UIString("Trace Log %d"), "profile-sidebar-tree-item");
  8927. },
  8928.  
  8929.  
  8930. createView: function(profilesPanel)
  8931. {
  8932. return new WebInspector.CanvasProfileView(this);
  8933. },
  8934.  
  8935. __proto__: WebInspector.ProfileHeader.prototype
  8936. }
  8937.  
  8938.  
  8939. WebInspector.CanvasLogGrid = function(traceLogId, linkifier)
  8940. {
  8941. this._linkifier = linkifier;
  8942. var columns = { 0: {}, 1: {}, 2: {} };
  8943. columns[0].title = "#";
  8944. columns[0].sortable = true;
  8945. columns[0].width = "3%";
  8946. columns[1].title = WebInspector.UIString("Call");
  8947. columns[1].sortable = true;
  8948. columns[1].width = "77%";
  8949. columns[2].title = WebInspector.UIString("Location");
  8950. columns[2].sortable = true;
  8951. columns[2].width = "20%";
  8952.  
  8953. WebInspector.DataGrid.call(this, columns);
  8954. this.element.addStyleClass("fill");
  8955.  
  8956. this._traceLogId = traceLogId;
  8957. CanvasAgent.getTraceLog(traceLogId, this._didReceiveTraceLog.bind(this));
  8958. }
  8959.  
  8960. WebInspector.CanvasLogGrid.prototype = {
  8961.  
  8962. _didReceiveTraceLog: function(error, traceLog)
  8963. {
  8964. this.rootNode().removeChildren();
  8965. if (error || !traceLog)
  8966. return;
  8967.  
  8968. var calls = traceLog.calls;
  8969. for (var i = 0, n = calls.length; i < n; ++i)
  8970. this.rootNode().appendChild(this._createCallNode(i, calls[i]));
  8971. var lastNode = this.rootNode().children[calls.length - 1];
  8972. if (lastNode) {
  8973. lastNode.reveal();
  8974. lastNode.select();
  8975. }
  8976. },
  8977.  
  8978. _createCallNode: function(index, call)
  8979. {
  8980. var traceLogItem = document.createElement("div");
  8981. var data = {};
  8982. data[0] = index + 1;
  8983. data[1] = call.functionName || "context." + call.property;
  8984. data[2] = "";
  8985. if (call.sourceURL) {
  8986.  
  8987. var lineNumber = Math.max(0, call.lineNumber - 1) || 0;
  8988. var columnNumber = Math.max(0, call.columnNumber - 1) || 0;
  8989. data[2] = this._linkifier.linkifyLocation(call.sourceURL, lineNumber, columnNumber);
  8990. }
  8991.  
  8992. if (call.arguments)
  8993. data[1] += "(" + call.arguments.join(", ") + ")";
  8994. else
  8995. data[1] += " = " + call.value;
  8996.  
  8997. if (typeof call.result !== "undefined")
  8998. data[1] += " => " + call.result;
  8999.  
  9000. var node = new WebInspector.DataGridNode(data);
  9001. node.call = call;
  9002. node.index = index;
  9003. node.selectable = true;
  9004. return node;
  9005. },
  9006.  
  9007. __proto__: WebInspector.DataGrid.prototype
  9008. }
  9009. ;
  9010.